diff options
Diffstat (limited to 'vendor/gioui.org/internal')
24 files changed, 8681 insertions, 224 deletions
diff --git a/vendor/gioui.org/internal/byteslice/byteslice.go b/vendor/gioui.org/internal/byteslice/byteslice.go new file mode 100644 index 0000000..26ebdb2 --- /dev/null +++ b/vendor/gioui.org/internal/byteslice/byteslice.go @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +// Package byteslice provides byte slice views of other Go values such as +// slices and structs. +package byteslice + +import ( + "reflect" + "unsafe" +) + +// Struct returns a byte slice view of a struct. +func Struct(s interface{}) []byte { + v := reflect.ValueOf(s).Elem() + sz := int(v.Type().Size()) + var res []byte + h := (*reflect.SliceHeader)(unsafe.Pointer(&res)) + h.Data = uintptr(unsafe.Pointer(v.UnsafeAddr())) + h.Cap = sz + h.Len = sz + return res +} + +// Uint32 returns a byte slice view of a uint32 slice. +func Uint32(s []uint32) []byte { + n := len(s) + if n == 0 { + return nil + } + blen := n * int(unsafe.Sizeof(s[0])) + return (*[1 << 30]byte)(unsafe.Pointer(&s[0]))[:blen:blen] +} + +// Slice returns a byte slice view of a slice. +func Slice(s interface{}) []byte { + v := reflect.ValueOf(s) + first := v.Index(0) + sz := int(first.Type().Size()) + var res []byte + h := (*reflect.SliceHeader)(unsafe.Pointer(&res)) + h.Data = first.UnsafeAddr() + h.Cap = v.Cap() * sz + h.Len = v.Len() * sz + return res +} diff --git a/vendor/gioui.org/internal/cocoainit/cocoa_darwin.go b/vendor/gioui.org/internal/cocoainit/cocoa_darwin.go new file mode 100644 index 0000000..2a34e57 --- /dev/null +++ b/vendor/gioui.org/internal/cocoainit/cocoa_darwin.go @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +// Package cocoainit initializes support for multithreaded +// programs in Cocoa. +package cocoainit + +/* +#cgo CFLAGS: -xobjective-c -fmodules -fobjc-arc +#import <Foundation/Foundation.h> + +static inline void activate_cocoa_multithreading() { + [[NSThread new] start]; +} +#pragma GCC visibility push(hidden) +*/ +import "C" + +func init() { + C.activate_cocoa_multithreading() +} diff --git a/vendor/gioui.org/internal/d3d11/d3d11_windows.go b/vendor/gioui.org/internal/d3d11/d3d11_windows.go new file mode 100644 index 0000000..450fde1 --- /dev/null +++ b/vendor/gioui.org/internal/d3d11/d3d11_windows.go @@ -0,0 +1,1682 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +package d3d11 + +import ( + "fmt" + "math" + "syscall" + "unsafe" + + "gioui.org/internal/f32color" + + "golang.org/x/sys/windows" +) + +type DXGI_SWAP_CHAIN_DESC struct { + BufferDesc DXGI_MODE_DESC + SampleDesc DXGI_SAMPLE_DESC + BufferUsage uint32 + BufferCount uint32 + OutputWindow windows.Handle + Windowed uint32 + SwapEffect uint32 + Flags uint32 +} + +type DXGI_SAMPLE_DESC struct { + Count uint32 + Quality uint32 +} + +type DXGI_MODE_DESC struct { + Width uint32 + Height uint32 + RefreshRate DXGI_RATIONAL + Format uint32 + ScanlineOrdering uint32 + Scaling uint32 +} + +type DXGI_RATIONAL struct { + Numerator uint32 + Denominator uint32 +} + +type TEXTURE2D_DESC struct { + Width uint32 + Height uint32 + MipLevels uint32 + ArraySize uint32 + Format uint32 + SampleDesc DXGI_SAMPLE_DESC + Usage uint32 + BindFlags uint32 + CPUAccessFlags uint32 + MiscFlags uint32 +} + +type SAMPLER_DESC struct { + Filter uint32 + AddressU uint32 + AddressV uint32 + AddressW uint32 + MipLODBias float32 + MaxAnisotropy uint32 + ComparisonFunc uint32 + BorderColor [4]float32 + MinLOD float32 + MaxLOD float32 +} + +type SHADER_RESOURCE_VIEW_DESC_TEX2D struct { + SHADER_RESOURCE_VIEW_DESC + Texture2D TEX2D_SRV +} + +type SHADER_RESOURCE_VIEW_DESC_BUFFEREX struct { + SHADER_RESOURCE_VIEW_DESC + Buffer BUFFEREX_SRV +} + +type UNORDERED_ACCESS_VIEW_DESC_TEX2D struct { + UNORDERED_ACCESS_VIEW_DESC + Texture2D TEX2D_UAV +} + +type UNORDERED_ACCESS_VIEW_DESC_BUFFER struct { + UNORDERED_ACCESS_VIEW_DESC + Buffer BUFFER_UAV +} + +type SHADER_RESOURCE_VIEW_DESC struct { + Format uint32 + ViewDimension uint32 +} + +type UNORDERED_ACCESS_VIEW_DESC struct { + Format uint32 + ViewDimension uint32 +} + +type TEX2D_SRV struct { + MostDetailedMip uint32 + MipLevels uint32 +} + +type BUFFEREX_SRV struct { + FirstElement uint32 + NumElements uint32 + Flags uint32 +} + +type TEX2D_UAV struct { + MipSlice uint32 +} + +type BUFFER_UAV struct { + FirstElement uint32 + NumElements uint32 + Flags uint32 +} + +type INPUT_ELEMENT_DESC struct { + SemanticName *byte + SemanticIndex uint32 + Format uint32 + InputSlot uint32 + AlignedByteOffset uint32 + InputSlotClass uint32 + InstanceDataStepRate uint32 +} + +type IDXGISwapChain struct { + Vtbl *struct { + _IUnknownVTbl + SetPrivateData uintptr + SetPrivateDataInterface uintptr + GetPrivateData uintptr + GetParent uintptr + GetDevice uintptr + Present uintptr + GetBuffer uintptr + SetFullscreenState uintptr + GetFullscreenState uintptr + GetDesc uintptr + ResizeBuffers uintptr + ResizeTarget uintptr + GetContainingOutput uintptr + GetFrameStatistics uintptr + GetLastPresentCount uintptr + } +} + +type Debug struct { + Vtbl *struct { + _IUnknownVTbl + SetFeatureMask uintptr + GetFeatureMask uintptr + SetPresentPerRenderOpDelay uintptr + GetPresentPerRenderOpDelay uintptr + SetSwapChain uintptr + GetSwapChain uintptr + ValidateContext uintptr + ReportLiveDeviceObjects uintptr + ValidateContextForDispatch uintptr + } +} + +type Device struct { + Vtbl *struct { + _IUnknownVTbl + CreateBuffer uintptr + CreateTexture1D uintptr + CreateTexture2D uintptr + CreateTexture3D uintptr + CreateShaderResourceView uintptr + CreateUnorderedAccessView uintptr + CreateRenderTargetView uintptr + CreateDepthStencilView uintptr + CreateInputLayout uintptr + CreateVertexShader uintptr + CreateGeometryShader uintptr + CreateGeometryShaderWithStreamOutput uintptr + CreatePixelShader uintptr + CreateHullShader uintptr + CreateDomainShader uintptr + CreateComputeShader uintptr + CreateClassLinkage uintptr + CreateBlendState uintptr + CreateDepthStencilState uintptr + CreateRasterizerState uintptr + CreateSamplerState uintptr + CreateQuery uintptr + CreatePredicate uintptr + CreateCounter uintptr + CreateDeferredContext uintptr + OpenSharedResource uintptr + CheckFormatSupport uintptr + CheckMultisampleQualityLevels uintptr + CheckCounterInfo uintptr + CheckCounter uintptr + CheckFeatureSupport uintptr + GetPrivateData uintptr + SetPrivateData uintptr + SetPrivateDataInterface uintptr + GetFeatureLevel uintptr + GetCreationFlags uintptr + GetDeviceRemovedReason uintptr + GetImmediateContext uintptr + SetExceptionMode uintptr + GetExceptionMode uintptr + } +} + +type DeviceContext struct { + Vtbl *struct { + _IUnknownVTbl + GetDevice uintptr + GetPrivateData uintptr + SetPrivateData uintptr + SetPrivateDataInterface uintptr + VSSetConstantBuffers uintptr + PSSetShaderResources uintptr + PSSetShader uintptr + PSSetSamplers uintptr + VSSetShader uintptr + DrawIndexed uintptr + Draw uintptr + Map uintptr + Unmap uintptr + PSSetConstantBuffers uintptr + IASetInputLayout uintptr + IASetVertexBuffers uintptr + IASetIndexBuffer uintptr + DrawIndexedInstanced uintptr + DrawInstanced uintptr + GSSetConstantBuffers uintptr + GSSetShader uintptr + IASetPrimitiveTopology uintptr + VSSetShaderResources uintptr + VSSetSamplers uintptr + Begin uintptr + End uintptr + GetData uintptr + SetPredication uintptr + GSSetShaderResources uintptr + GSSetSamplers uintptr + OMSetRenderTargets uintptr + OMSetRenderTargetsAndUnorderedAccessViews uintptr + OMSetBlendState uintptr + OMSetDepthStencilState uintptr + SOSetTargets uintptr + DrawAuto uintptr + DrawIndexedInstancedIndirect uintptr + DrawInstancedIndirect uintptr + Dispatch uintptr + DispatchIndirect uintptr + RSSetState uintptr + RSSetViewports uintptr + RSSetScissorRects uintptr + CopySubresourceRegion uintptr + CopyResource uintptr + UpdateSubresource uintptr + CopyStructureCount uintptr + ClearRenderTargetView uintptr + ClearUnorderedAccessViewUint uintptr + ClearUnorderedAccessViewFloat uintptr + ClearDepthStencilView uintptr + GenerateMips uintptr + SetResourceMinLOD uintptr + GetResourceMinLOD uintptr + ResolveSubresource uintptr + ExecuteCommandList uintptr + HSSetShaderResources uintptr + HSSetShader uintptr + HSSetSamplers uintptr + HSSetConstantBuffers uintptr + DSSetShaderResources uintptr + DSSetShader uintptr + DSSetSamplers uintptr + DSSetConstantBuffers uintptr + CSSetShaderResources uintptr + CSSetUnorderedAccessViews uintptr + CSSetShader uintptr + CSSetSamplers uintptr + CSSetConstantBuffers uintptr + VSGetConstantBuffers uintptr + PSGetShaderResources uintptr + PSGetShader uintptr + PSGetSamplers uintptr + VSGetShader uintptr + PSGetConstantBuffers uintptr + IAGetInputLayout uintptr + IAGetVertexBuffers uintptr + IAGetIndexBuffer uintptr + GSGetConstantBuffers uintptr + GSGetShader uintptr + IAGetPrimitiveTopology uintptr + VSGetShaderResources uintptr + VSGetSamplers uintptr + GetPredication uintptr + GSGetShaderResources uintptr + GSGetSamplers uintptr + OMGetRenderTargets uintptr + OMGetRenderTargetsAndUnorderedAccessViews uintptr + OMGetBlendState uintptr + OMGetDepthStencilState uintptr + SOGetTargets uintptr + RSGetState uintptr + RSGetViewports uintptr + RSGetScissorRects uintptr + HSGetShaderResources uintptr + HSGetShader uintptr + HSGetSamplers uintptr + HSGetConstantBuffers uintptr + DSGetShaderResources uintptr + DSGetShader uintptr + DSGetSamplers uintptr + DSGetConstantBuffers uintptr + CSGetShaderResources uintptr + CSGetUnorderedAccessViews uintptr + CSGetShader uintptr + CSGetSamplers uintptr + CSGetConstantBuffers uintptr + ClearState uintptr + Flush uintptr + GetType uintptr + GetContextFlags uintptr + FinishCommandList uintptr + } +} + +type RenderTargetView struct { + Vtbl *struct { + _IUnknownVTbl + } +} + +type Resource struct { + Vtbl *struct { + _IUnknownVTbl + } +} + +type Texture2D struct { + Vtbl *struct { + _IUnknownVTbl + } +} + +type Buffer struct { + Vtbl *struct { + _IUnknownVTbl + } +} + +type SamplerState struct { + Vtbl *struct { + _IUnknownVTbl + } +} + +type PixelShader struct { + Vtbl *struct { + _IUnknownVTbl + } +} + +type ShaderResourceView struct { + Vtbl *struct { + _IUnknownVTbl + } +} + +type UnorderedAccessView struct { + Vtbl *struct { + _IUnknownVTbl + } +} + +type DepthStencilView struct { + Vtbl *struct { + _IUnknownVTbl + } +} + +type BlendState struct { + Vtbl *struct { + _IUnknownVTbl + } +} + +type DepthStencilState struct { + Vtbl *struct { + _IUnknownVTbl + } +} + +type VertexShader struct { + Vtbl *struct { + _IUnknownVTbl + } +} + +type ComputeShader struct { + Vtbl *struct { + _IUnknownVTbl + } +} + +type RasterizerState struct { + Vtbl *struct { + _IUnknownVTbl + } +} + +type InputLayout struct { + Vtbl *struct { + _IUnknownVTbl + GetBufferPointer uintptr + GetBufferSize uintptr + } +} + +type DEPTH_STENCIL_DESC struct { + DepthEnable uint32 + DepthWriteMask uint32 + DepthFunc uint32 + StencilEnable uint32 + StencilReadMask uint8 + StencilWriteMask uint8 + FrontFace DEPTH_STENCILOP_DESC + BackFace DEPTH_STENCILOP_DESC +} + +type DEPTH_STENCILOP_DESC struct { + StencilFailOp uint32 + StencilDepthFailOp uint32 + StencilPassOp uint32 + StencilFunc uint32 +} + +type DEPTH_STENCIL_VIEW_DESC_TEX2D struct { + Format uint32 + ViewDimension uint32 + Flags uint32 + Texture2D TEX2D_DSV +} + +type TEX2D_DSV struct { + MipSlice uint32 +} + +type BLEND_DESC struct { + AlphaToCoverageEnable uint32 + IndependentBlendEnable uint32 + RenderTarget [8]RENDER_TARGET_BLEND_DESC +} + +type RENDER_TARGET_BLEND_DESC struct { + BlendEnable uint32 + SrcBlend uint32 + DestBlend uint32 + BlendOp uint32 + SrcBlendAlpha uint32 + DestBlendAlpha uint32 + BlendOpAlpha uint32 + RenderTargetWriteMask uint8 +} + +type IDXGIObject struct { + Vtbl *struct { + _IUnknownVTbl + SetPrivateData uintptr + SetPrivateDataInterface uintptr + GetPrivateData uintptr + GetParent uintptr + } +} + +type IDXGIAdapter struct { + Vtbl *struct { + _IUnknownVTbl + SetPrivateData uintptr + SetPrivateDataInterface uintptr + GetPrivateData uintptr + GetParent uintptr + EnumOutputs uintptr + GetDesc uintptr + CheckInterfaceSupport uintptr + GetDesc1 uintptr + } +} + +type IDXGIFactory struct { + Vtbl *struct { + _IUnknownVTbl + SetPrivateData uintptr + SetPrivateDataInterface uintptr + GetPrivateData uintptr + GetParent uintptr + EnumAdapters uintptr + MakeWindowAssociation uintptr + GetWindowAssociation uintptr + CreateSwapChain uintptr + CreateSoftwareAdapter uintptr + } +} + +type IDXGIDebug struct { + Vtbl *struct { + _IUnknownVTbl + ReportLiveObjects uintptr + } +} + +type IDXGIDevice struct { + Vtbl *struct { + _IUnknownVTbl + SetPrivateData uintptr + SetPrivateDataInterface uintptr + GetPrivateData uintptr + GetParent uintptr + GetAdapter uintptr + CreateSurface uintptr + QueryResourceResidency uintptr + SetGPUThreadPriority uintptr + GetGPUThreadPriority uintptr + } +} + +type IUnknown struct { + Vtbl *struct { + _IUnknownVTbl + } +} + +type _IUnknownVTbl struct { + QueryInterface uintptr + AddRef uintptr + Release uintptr +} + +type BUFFER_DESC struct { + ByteWidth uint32 + Usage uint32 + BindFlags uint32 + CPUAccessFlags uint32 + MiscFlags uint32 + StructureByteStride uint32 +} + +type GUID struct { + Data1 uint32 + Data2 uint16 + Data3 uint16 + Data4_0 uint8 + Data4_1 uint8 + Data4_2 uint8 + Data4_3 uint8 + Data4_4 uint8 + Data4_5 uint8 + Data4_6 uint8 + Data4_7 uint8 +} + +type VIEWPORT struct { + TopLeftX float32 + TopLeftY float32 + Width float32 + Height float32 + MinDepth float32 + MaxDepth float32 +} + +type SUBRESOURCE_DATA struct { + pSysMem *byte +} + +type BOX struct { + Left uint32 + Top uint32 + Front uint32 + Right uint32 + Bottom uint32 + Back uint32 +} + +type MAPPED_SUBRESOURCE struct { + PData uintptr + RowPitch uint32 + DepthPitch uint32 +} + +type ErrorCode struct { + Name string + Code uint32 +} + +type RASTERIZER_DESC struct { + FillMode uint32 + CullMode uint32 + FrontCounterClockwise uint32 + DepthBias int32 + DepthBiasClamp float32 + SlopeScaledDepthBias float32 + DepthClipEnable uint32 + ScissorEnable uint32 + MultisampleEnable uint32 + AntialiasedLineEnable uint32 +} + +var ( + IID_Texture2D = GUID{0x6f15aaf2, 0xd208, 0x4e89, 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3, 0x4f, 0x9c} + IID_IDXGIDebug = GUID{0x119E7452, 0xDE9E, 0x40fe, 0x88, 0x06, 0x88, 0xF9, 0x0C, 0x12, 0xB4, 0x41} + IID_IDXGIDevice = GUID{0x54ec77fa, 0x1377, 0x44e6, 0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8, 0x4c} + IID_IDXGIFactory = GUID{0x7b7166ec, 0x21c7, 0x44ae, 0xb2, 0x1a, 0xc9, 0xae, 0x32, 0x1a, 0xe3, 0x69} + IID_ID3D11Debug = GUID{0x79cf2233, 0x7536, 0x4948, 0x9d, 0x36, 0x1e, 0x46, 0x92, 0xdc, 0x57, 0x60} + + DXGI_DEBUG_ALL = GUID{0xe48ae283, 0xda80, 0x490b, 0x87, 0xe6, 0x43, 0xe9, 0xa9, 0xcf, 0xda, 0x8} +) + +var ( + d3d11 = windows.NewLazySystemDLL("d3d11.dll") + + _D3D11CreateDevice = d3d11.NewProc("D3D11CreateDevice") + _D3D11CreateDeviceAndSwapChain = d3d11.NewProc("D3D11CreateDeviceAndSwapChain") + + dxgi = windows.NewLazySystemDLL("dxgi.dll") + + _DXGIGetDebugInterface1 = dxgi.NewProc("DXGIGetDebugInterface1") +) + +const ( + SDK_VERSION = 7 + DRIVER_TYPE_HARDWARE = 1 + + DXGI_FORMAT_UNKNOWN = 0 + DXGI_FORMAT_R16_FLOAT = 54 + DXGI_FORMAT_R32_FLOAT = 41 + DXGI_FORMAT_R32_TYPELESS = 39 + DXGI_FORMAT_R32G32_FLOAT = 16 + DXGI_FORMAT_R32G32B32_FLOAT = 6 + DXGI_FORMAT_R32G32B32A32_FLOAT = 2 + DXGI_FORMAT_R8G8B8A8_UNORM = 28 + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29 + DXGI_FORMAT_R16_SINT = 59 + DXGI_FORMAT_R16G16_SINT = 38 + DXGI_FORMAT_R16_UINT = 57 + DXGI_FORMAT_D24_UNORM_S8_UINT = 45 + DXGI_FORMAT_R16G16_FLOAT = 34 + DXGI_FORMAT_R16G16B16A16_FLOAT = 10 + + DXGI_DEBUG_RLO_SUMMARY = 0x1 + DXGI_DEBUG_RLO_DETAIL = 0x2 + DXGI_DEBUG_RLO_IGNORE_INTERNAL = 0x4 + + FORMAT_SUPPORT_TEXTURE2D = 0x20 + FORMAT_SUPPORT_RENDER_TARGET = 0x4000 + + DXGI_USAGE_RENDER_TARGET_OUTPUT = 1 << (1 + 4) + + CPU_ACCESS_READ = 0x20000 + + MAP_READ = 1 + + DXGI_SWAP_EFFECT_DISCARD = 0 + + FEATURE_LEVEL_9_1 = 0x9100 + FEATURE_LEVEL_9_3 = 0x9300 + FEATURE_LEVEL_11_0 = 0xb000 + + USAGE_IMMUTABLE = 1 + USAGE_STAGING = 3 + + BIND_VERTEX_BUFFER = 0x1 + BIND_INDEX_BUFFER = 0x2 + BIND_CONSTANT_BUFFER = 0x4 + BIND_SHADER_RESOURCE = 0x8 + BIND_RENDER_TARGET = 0x20 + BIND_DEPTH_STENCIL = 0x40 + BIND_UNORDERED_ACCESS = 0x80 + + PRIMITIVE_TOPOLOGY_TRIANGLELIST = 4 + PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = 5 + + FILTER_MIN_MAG_LINEAR_MIP_POINT = 0x14 + FILTER_MIN_MAG_MIP_POINT = 0 + + TEXTURE_ADDRESS_MIRROR = 2 + TEXTURE_ADDRESS_CLAMP = 3 + TEXTURE_ADDRESS_WRAP = 1 + + SRV_DIMENSION_BUFFER = 1 + UAV_DIMENSION_BUFFER = 1 + SRV_DIMENSION_BUFFEREX = 11 + SRV_DIMENSION_TEXTURE2D = 4 + UAV_DIMENSION_TEXTURE2D = 4 + + BUFFER_UAV_FLAG_RAW = 0x1 + BUFFEREX_SRV_FLAG_RAW = 0x1 + + RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS = 0x20 + + CREATE_DEVICE_DEBUG = 0x2 + + FILL_SOLID = 3 + + CULL_NONE = 1 + + CLEAR_DEPTH = 0x1 + CLEAR_STENCIL = 0x2 + + DSV_DIMENSION_TEXTURE2D = 3 + + DEPTH_WRITE_MASK_ALL = 1 + + COMPARISON_GREATER = 5 + COMPARISON_GREATER_EQUAL = 7 + + BLEND_OP_ADD = 1 + BLEND_ONE = 2 + BLEND_INV_SRC_ALPHA = 6 + BLEND_ZERO = 1 + BLEND_DEST_COLOR = 9 + BLEND_DEST_ALPHA = 7 + + COLOR_WRITE_ENABLE_ALL = 1 | 2 | 4 | 8 + + DXGI_STATUS_OCCLUDED = 0x087A0001 + DXGI_ERROR_DEVICE_RESET = 0x887A0007 + DXGI_ERROR_DEVICE_REMOVED = 0x887A0005 + D3DDDIERR_DEVICEREMOVED = 1<<31 | 0x876<<16 | 2160 + + RLDO_SUMMARY = 1 + RLDO_DETAIL = 2 + RLDO_IGNORE_INTERNAL = 4 +) + +func CreateDevice(driverType uint32, flags uint32) (*Device, *DeviceContext, uint32, error) { + var ( + dev *Device + ctx *DeviceContext + featLvl uint32 + ) + r, _, _ := _D3D11CreateDevice.Call( + 0, // pAdapter + uintptr(driverType), // driverType + 0, // Software + uintptr(flags), // Flags + 0, // pFeatureLevels + 0, // FeatureLevels + SDK_VERSION, // SDKVersion + uintptr(unsafe.Pointer(&dev)), // ppDevice + uintptr(unsafe.Pointer(&featLvl)), // pFeatureLevel + uintptr(unsafe.Pointer(&ctx)), // ppImmediateContext + ) + if r != 0 { + return nil, nil, 0, ErrorCode{Name: "D3D11CreateDevice", Code: uint32(r)} + } + return dev, ctx, featLvl, nil +} + +func CreateDeviceAndSwapChain(driverType uint32, flags uint32, swapDesc *DXGI_SWAP_CHAIN_DESC) (*Device, *DeviceContext, *IDXGISwapChain, uint32, error) { + var ( + dev *Device + ctx *DeviceContext + swchain *IDXGISwapChain + featLvl uint32 + ) + r, _, _ := _D3D11CreateDeviceAndSwapChain.Call( + 0, // pAdapter + uintptr(driverType), // driverType + 0, // Software + uintptr(flags), // Flags + 0, // pFeatureLevels + 0, // FeatureLevels + SDK_VERSION, // SDKVersion + uintptr(unsafe.Pointer(swapDesc)), // pSwapChainDesc + uintptr(unsafe.Pointer(&swchain)), // ppSwapChain + uintptr(unsafe.Pointer(&dev)), // ppDevice + uintptr(unsafe.Pointer(&featLvl)), // pFeatureLevel + uintptr(unsafe.Pointer(&ctx)), // ppImmediateContext + ) + if r != 0 { + return nil, nil, nil, 0, ErrorCode{Name: "D3D11CreateDeviceAndSwapChain", Code: uint32(r)} + } + return dev, ctx, swchain, featLvl, nil +} + +func DXGIGetDebugInterface1() (*IDXGIDebug, error) { + var dbg *IDXGIDebug + r, _, _ := _DXGIGetDebugInterface1.Call( + 0, // Flags + uintptr(unsafe.Pointer(&IID_IDXGIDebug)), + uintptr(unsafe.Pointer(&dbg)), + ) + if r != 0 { + return nil, ErrorCode{Name: "DXGIGetDebugInterface1", Code: uint32(r)} + } + return dbg, nil +} + +func ReportLiveObjects() error { + dxgi, err := DXGIGetDebugInterface1() + if err != nil { + return err + } + defer IUnknownRelease(unsafe.Pointer(dxgi), dxgi.Vtbl.Release) + dxgi.ReportLiveObjects(&DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_DETAIL|DXGI_DEBUG_RLO_IGNORE_INTERNAL) + return nil +} + +func (d *IDXGIDebug) ReportLiveObjects(guid *GUID, flags uint32) { + syscall.Syscall6( + d.Vtbl.ReportLiveObjects, + 3, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(guid)), + uintptr(flags), + 0, + 0, + 0, + ) +} + +func (d *Device) CheckFormatSupport(format uint32) (uint32, error) { + var support uint32 + r, _, _ := syscall.Syscall( + d.Vtbl.CheckFormatSupport, + 3, + uintptr(unsafe.Pointer(d)), + uintptr(format), + uintptr(unsafe.Pointer(&support)), + ) + if r != 0 { + return 0, ErrorCode{Name: "DeviceCheckFormatSupport", Code: uint32(r)} + } + return support, nil +} + +func (d *Device) CreateBuffer(desc *BUFFER_DESC, data []byte) (*Buffer, error) { + var dataDesc *SUBRESOURCE_DATA + if len(data) > 0 { + dataDesc = &SUBRESOURCE_DATA{ + pSysMem: &data[0], + } + } + var buf *Buffer + r, _, _ := syscall.Syscall6( + d.Vtbl.CreateBuffer, + 4, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(desc)), + uintptr(unsafe.Pointer(dataDesc)), + uintptr(unsafe.Pointer(&buf)), + 0, 0, + ) + if r != 0 { + return nil, ErrorCode{Name: "DeviceCreateBuffer", Code: uint32(r)} + } + return buf, nil +} + +func (d *Device) CreateDepthStencilViewTEX2D(res *Resource, desc *DEPTH_STENCIL_VIEW_DESC_TEX2D) (*DepthStencilView, error) { + var view *DepthStencilView + r, _, _ := syscall.Syscall6( + d.Vtbl.CreateDepthStencilView, + 4, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(res)), + uintptr(unsafe.Pointer(desc)), + uintptr(unsafe.Pointer(&view)), + 0, 0, + ) + if r != 0 { + return nil, ErrorCode{Name: "DeviceCreateDepthStencilView", Code: uint32(r)} + } + return view, nil +} + +func (d *Device) CreatePixelShader(bytecode []byte) (*PixelShader, error) { + var shader *PixelShader + r, _, _ := syscall.Syscall6( + d.Vtbl.CreatePixelShader, + 5, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(&bytecode[0])), + uintptr(len(bytecode)), + 0, // pClassLinkage + uintptr(unsafe.Pointer(&shader)), + 0, + ) + if r != 0 { + return nil, ErrorCode{Name: "DeviceCreatePixelShader", Code: uint32(r)} + } + return shader, nil +} + +func (d *Device) CreateVertexShader(bytecode []byte) (*VertexShader, error) { + var shader *VertexShader + r, _, _ := syscall.Syscall6( + d.Vtbl.CreateVertexShader, + 5, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(&bytecode[0])), + uintptr(len(bytecode)), + 0, // pClassLinkage + uintptr(unsafe.Pointer(&shader)), + 0, + ) + if r != 0 { + return nil, ErrorCode{Name: "DeviceCreateVertexShader", Code: uint32(r)} + } + return shader, nil +} + +func (d *Device) CreateComputeShader(bytecode []byte) (*ComputeShader, error) { + var shader *ComputeShader + r, _, _ := syscall.Syscall6( + d.Vtbl.CreateComputeShader, + 5, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(&bytecode[0])), + uintptr(len(bytecode)), + 0, // pClassLinkage + uintptr(unsafe.Pointer(&shader)), + 0, + ) + if r != 0 { + return nil, ErrorCode{Name: "DeviceCreateComputeShader", Code: uint32(r)} + } + return shader, nil +} + +func (d *Device) CreateShaderResourceView(res *Resource, desc unsafe.Pointer) (*ShaderResourceView, error) { + var resView *ShaderResourceView + r, _, _ := syscall.Syscall6( + d.Vtbl.CreateShaderResourceView, + 4, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(res)), + uintptr(desc), + uintptr(unsafe.Pointer(&resView)), + 0, 0, + ) + if r != 0 { + return nil, ErrorCode{Name: "DeviceCreateShaderResourceView", Code: uint32(r)} + } + return resView, nil +} + +func (d *Device) CreateUnorderedAccessView(res *Resource, desc unsafe.Pointer) (*UnorderedAccessView, error) { + var uaView *UnorderedAccessView + r, _, _ := syscall.Syscall6( + d.Vtbl.CreateUnorderedAccessView, + 4, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(res)), + uintptr(desc), + uintptr(unsafe.Pointer(&uaView)), + 0, 0, + ) + if r != 0 { + return nil, ErrorCode{Name: "DeviceCreateUnorderedAccessView", Code: uint32(r)} + } + return uaView, nil +} + +func (d *Device) CreateRasterizerState(desc *RASTERIZER_DESC) (*RasterizerState, error) { + var state *RasterizerState + r, _, _ := syscall.Syscall( + d.Vtbl.CreateRasterizerState, + 3, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(desc)), + uintptr(unsafe.Pointer(&state)), + ) + if r != 0 { + return nil, ErrorCode{Name: "DeviceCreateRasterizerState", Code: uint32(r)} + } + return state, nil +} + +func (d *Device) CreateInputLayout(descs []INPUT_ELEMENT_DESC, bytecode []byte) (*InputLayout, error) { + var pdesc *INPUT_ELEMENT_DESC + if len(descs) > 0 { + pdesc = &descs[0] + } + var layout *InputLayout + r, _, _ := syscall.Syscall6( + d.Vtbl.CreateInputLayout, + 6, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(pdesc)), + uintptr(len(descs)), + uintptr(unsafe.Pointer(&bytecode[0])), + uintptr(len(bytecode)), + uintptr(unsafe.Pointer(&layout)), + ) + if r != 0 { + return nil, ErrorCode{Name: "DeviceCreateInputLayout", Code: uint32(r)} + } + return layout, nil +} + +func (d *Device) CreateSamplerState(desc *SAMPLER_DESC) (*SamplerState, error) { + var sampler *SamplerState + r, _, _ := syscall.Syscall( + d.Vtbl.CreateSamplerState, + 3, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(desc)), + uintptr(unsafe.Pointer(&sampler)), + ) + if r != 0 { + return nil, ErrorCode{Name: "DeviceCreateSamplerState", Code: uint32(r)} + } + return sampler, nil +} + +func (d *Device) CreateTexture2D(desc *TEXTURE2D_DESC) (*Texture2D, error) { + var tex *Texture2D + r, _, _ := syscall.Syscall6( + d.Vtbl.CreateTexture2D, + 4, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(desc)), + 0, // pInitialData + uintptr(unsafe.Pointer(&tex)), + 0, 0, + ) + if r != 0 { + return nil, ErrorCode{Name: "CreateTexture2D", Code: uint32(r)} + } + return tex, nil +} + +func (d *Device) CreateRenderTargetView(res *Resource) (*RenderTargetView, error) { + var target *RenderTargetView + r, _, _ := syscall.Syscall6( + d.Vtbl.CreateRenderTargetView, + 4, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(res)), + 0, // pDesc + uintptr(unsafe.Pointer(&target)), + 0, 0, + ) + if r != 0 { + return nil, ErrorCode{Name: "DeviceCreateRenderTargetView", Code: uint32(r)} + } + return target, nil +} + +func (d *Device) CreateBlendState(desc *BLEND_DESC) (*BlendState, error) { + var state *BlendState + r, _, _ := syscall.Syscall( + d.Vtbl.CreateBlendState, + 3, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(desc)), + uintptr(unsafe.Pointer(&state)), + ) + if r != 0 { + return nil, ErrorCode{Name: "DeviceCreateBlendState", Code: uint32(r)} + } + return state, nil +} + +func (d *Device) CreateDepthStencilState(desc *DEPTH_STENCIL_DESC) (*DepthStencilState, error) { + var state *DepthStencilState + r, _, _ := syscall.Syscall( + d.Vtbl.CreateDepthStencilState, + 3, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(desc)), + uintptr(unsafe.Pointer(&state)), + ) + if r != 0 { + return nil, ErrorCode{Name: "DeviceCreateDepthStencilState", Code: uint32(r)} + } + return state, nil +} + +func (d *Device) GetFeatureLevel() int { + lvl, _, _ := syscall.Syscall( + d.Vtbl.GetFeatureLevel, + 1, + uintptr(unsafe.Pointer(d)), + 0, 0, + ) + return int(lvl) +} + +func (d *Device) GetImmediateContext() *DeviceContext { + var ctx *DeviceContext + syscall.Syscall( + d.Vtbl.GetImmediateContext, + 2, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(&ctx)), + 0, + ) + return ctx +} + +func (d *Device) ReportLiveDeviceObjects() error { + intf, err := IUnknownQueryInterface(unsafe.Pointer(d), d.Vtbl.QueryInterface, &IID_ID3D11Debug) + if err != nil { + return fmt.Errorf("ReportLiveObjects: failed to query ID3D11Debug interface: %v", err) + } + defer IUnknownRelease(unsafe.Pointer(intf), intf.Vtbl.Release) + dbg := (*Debug)(unsafe.Pointer(intf)) + dbg.ReportLiveDeviceObjects(RLDO_DETAIL | RLDO_IGNORE_INTERNAL) + return nil +} + +func (d *Debug) ReportLiveDeviceObjects(flags uint32) { + syscall.Syscall( + d.Vtbl.ReportLiveDeviceObjects, + 2, + uintptr(unsafe.Pointer(d)), + uintptr(flags), + 0, + ) +} + +func (s *IDXGISwapChain) GetDesc() (DXGI_SWAP_CHAIN_DESC, error) { + var desc DXGI_SWAP_CHAIN_DESC + r, _, _ := syscall.Syscall( + s.Vtbl.GetDesc, + 2, + uintptr(unsafe.Pointer(s)), + uintptr(unsafe.Pointer(&desc)), + 0, + ) + if r != 0 { + return DXGI_SWAP_CHAIN_DESC{}, ErrorCode{Name: "IDXGISwapChainGetDesc", Code: uint32(r)} + } + return desc, nil +} + +func (s *IDXGISwapChain) ResizeBuffers(buffers, width, height, newFormat, flags uint32) error { + r, _, _ := syscall.Syscall6( + s.Vtbl.ResizeBuffers, + 6, + uintptr(unsafe.Pointer(s)), + uintptr(buffers), + uintptr(width), + uintptr(height), + uintptr(newFormat), + uintptr(flags), + ) + if r != 0 { + return ErrorCode{Name: "IDXGISwapChainResizeBuffers", Code: uint32(r)} + } + return nil +} + +func (s *IDXGISwapChain) Present(SyncInterval int, Flags uint32) error { + r, _, _ := syscall.Syscall( + s.Vtbl.Present, + 3, + uintptr(unsafe.Pointer(s)), + uintptr(SyncInterval), + uintptr(Flags), + ) + if r != 0 { + return ErrorCode{Name: "IDXGISwapChainPresent", Code: uint32(r)} + } + return nil +} + +func (s *IDXGISwapChain) GetBuffer(index int, riid *GUID) (*IUnknown, error) { + var buf *IUnknown + r, _, _ := syscall.Syscall6( + s.Vtbl.GetBuffer, + 4, + uintptr(unsafe.Pointer(s)), + uintptr(index), + uintptr(unsafe.Pointer(riid)), + uintptr(unsafe.Pointer(&buf)), + 0, + 0, + ) + if r != 0 { + return nil, ErrorCode{Name: "IDXGISwapChainGetBuffer", Code: uint32(r)} + } + return buf, nil +} + +func (c *DeviceContext) Unmap(resource *Resource, subResource uint32) { + syscall.Syscall( + c.Vtbl.Unmap, + 3, + uintptr(unsafe.Pointer(c)), + uintptr(unsafe.Pointer(resource)), + uintptr(subResource), + ) +} + +func (c *DeviceContext) Map(resource *Resource, subResource, mapType, mapFlags uint32) (MAPPED_SUBRESOURCE, error) { + var resMap MAPPED_SUBRESOURCE + r, _, _ := syscall.Syscall6( + c.Vtbl.Map, + 6, + uintptr(unsafe.Pointer(c)), + uintptr(unsafe.Pointer(resource)), + uintptr(subResource), + uintptr(mapType), + uintptr(mapFlags), + uintptr(unsafe.Pointer(&resMap)), + ) + if r != 0 { + return resMap, ErrorCode{Name: "DeviceContextMap", Code: uint32(r)} + } + return resMap, nil +} + +func (c *DeviceContext) CopySubresourceRegion(dst *Resource, dstSubresource, dstX, dstY, dstZ uint32, src *Resource, srcSubresource uint32, srcBox *BOX) { + syscall.Syscall9( + c.Vtbl.CopySubresourceRegion, + 9, + uintptr(unsafe.Pointer(c)), + uintptr(unsafe.Pointer(dst)), + uintptr(dstSubresource), + uintptr(dstX), + uintptr(dstY), + uintptr(dstZ), + uintptr(unsafe.Pointer(src)), + uintptr(srcSubresource), + uintptr(unsafe.Pointer(srcBox)), + ) +} + +func (c *DeviceContext) ClearDepthStencilView(target *DepthStencilView, flags uint32, depth float32, stencil uint8) { + syscall.Syscall6( + c.Vtbl.ClearDepthStencilView, + 5, + uintptr(unsafe.Pointer(c)), + uintptr(unsafe.Pointer(target)), + uintptr(flags), + uintptr(math.Float32bits(depth)), + uintptr(stencil), + 0, + ) +} + +func (c *DeviceContext) ClearRenderTargetView(target *RenderTargetView, color *[4]float32) { + syscall.Syscall( + c.Vtbl.ClearRenderTargetView, + 3, + uintptr(unsafe.Pointer(c)), + uintptr(unsafe.Pointer(target)), + uintptr(unsafe.Pointer(color)), + ) +} + +func (c *DeviceContext) CSSetShaderResources(startSlot uint32, s *ShaderResourceView) { + syscall.Syscall6( + c.Vtbl.CSSetShaderResources, + 4, + uintptr(unsafe.Pointer(c)), + uintptr(startSlot), + 1, // NumViews + uintptr(unsafe.Pointer(&s)), + 0, 0, + ) +} + +func (c *DeviceContext) CSSetUnorderedAccessViews(startSlot uint32, v *UnorderedAccessView) { + syscall.Syscall6( + c.Vtbl.CSSetUnorderedAccessViews, + 4, + uintptr(unsafe.Pointer(c)), + uintptr(startSlot), + 1, // NumViews + uintptr(unsafe.Pointer(&v)), + 0, 0, + ) +} + +func (c *DeviceContext) CSSetShader(s *ComputeShader) { + syscall.Syscall6( + c.Vtbl.CSSetShader, + 4, + uintptr(unsafe.Pointer(c)), + uintptr(unsafe.Pointer(s)), + 0, // ppClassInstances + 0, // NumClassInstances + 0, 0, + ) +} + +func (c *DeviceContext) RSSetViewports(viewport *VIEWPORT) { + syscall.Syscall( + c.Vtbl.RSSetViewports, + 3, + uintptr(unsafe.Pointer(c)), + 1, // NumViewports + uintptr(unsafe.Pointer(viewport)), + ) +} + +func (c *DeviceContext) VSSetShader(s *VertexShader) { + syscall.Syscall6( + c.Vtbl.VSSetShader, + 4, + uintptr(unsafe.Pointer(c)), + uintptr(unsafe.Pointer(s)), + 0, // ppClassInstances + 0, // NumClassInstances + 0, 0, + ) +} + +func (c *DeviceContext) VSSetConstantBuffers(b *Buffer) { + syscall.Syscall6( + c.Vtbl.VSSetConstantBuffers, + 4, + uintptr(unsafe.Pointer(c)), + 0, // StartSlot + 1, // NumBuffers + uintptr(unsafe.Pointer(&b)), + 0, 0, + ) +} + +func (c *DeviceContext) PSSetConstantBuffers(b *Buffer) { + syscall.Syscall6( + c.Vtbl.PSSetConstantBuffers, + 4, + uintptr(unsafe.Pointer(c)), + 0, // StartSlot + 1, // NumBuffers + uintptr(unsafe.Pointer(&b)), + 0, 0, + ) +} + +func (c *DeviceContext) PSSetShaderResources(startSlot uint32, s *ShaderResourceView) { + syscall.Syscall6( + c.Vtbl.PSSetShaderResources, + 4, + uintptr(unsafe.Pointer(c)), + uintptr(startSlot), + 1, // NumViews + uintptr(unsafe.Pointer(&s)), + 0, 0, + ) +} + +func (c *DeviceContext) PSSetSamplers(startSlot uint32, s *SamplerState) { + syscall.Syscall6( + c.Vtbl.PSSetSamplers, + 4, + uintptr(unsafe.Pointer(c)), + uintptr(startSlot), + 1, // NumSamplers + uintptr(unsafe.Pointer(&s)), + 0, 0, + ) +} + +func (c *DeviceContext) PSSetShader(s *PixelShader) { + syscall.Syscall6( + c.Vtbl.PSSetShader, + 4, + uintptr(unsafe.Pointer(c)), + uintptr(unsafe.Pointer(s)), + 0, // ppClassInstances + 0, // NumClassInstances + 0, 0, + ) +} + +func (c *DeviceContext) UpdateSubresource(res *Resource, dstBox *BOX, rowPitch, depthPitch uint32, data []byte) { + syscall.Syscall9( + c.Vtbl.UpdateSubresource, + 7, + uintptr(unsafe.Pointer(c)), + uintptr(unsafe.Pointer(res)), + 0, // DstSubresource + uintptr(unsafe.Pointer(dstBox)), + uintptr(unsafe.Pointer(&data[0])), + uintptr(rowPitch), + uintptr(depthPitch), + 0, 0, + ) +} + +func (c *DeviceContext) RSSetState(state *RasterizerState) { + syscall.Syscall( + c.Vtbl.RSSetState, + 2, + uintptr(unsafe.Pointer(c)), + uintptr(unsafe.Pointer(state)), + 0, + ) +} + +func (c *DeviceContext) IASetInputLayout(layout *InputLayout) { + syscall.Syscall( + c.Vtbl.IASetInputLayout, + 2, + uintptr(unsafe.Pointer(c)), + uintptr(unsafe.Pointer(layout)), + 0, + ) +} + +func (c *DeviceContext) IASetIndexBuffer(buf *Buffer, format, offset uint32) { + syscall.Syscall6( + c.Vtbl.IASetIndexBuffer, + 4, + uintptr(unsafe.Pointer(c)), + uintptr(unsafe.Pointer(buf)), + uintptr(format), + uintptr(offset), + 0, 0, + ) +} + +func (c *DeviceContext) IASetVertexBuffers(buf *Buffer, stride, offset uint32) { + syscall.Syscall6( + c.Vtbl.IASetVertexBuffers, + 6, + uintptr(unsafe.Pointer(c)), + 0, // StartSlot + 1, // NumBuffers, + uintptr(unsafe.Pointer(&buf)), + uintptr(unsafe.Pointer(&stride)), + uintptr(unsafe.Pointer(&offset)), + ) +} + +func (c *DeviceContext) IASetPrimitiveTopology(mode uint32) { + syscall.Syscall( + c.Vtbl.IASetPrimitiveTopology, + 2, + uintptr(unsafe.Pointer(c)), + uintptr(mode), + 0, + ) +} + +func (c *DeviceContext) OMGetRenderTargets() (*RenderTargetView, *DepthStencilView) { + var ( + target *RenderTargetView + depthStencilView *DepthStencilView + ) + syscall.Syscall6( + c.Vtbl.OMGetRenderTargets, + 4, + uintptr(unsafe.Pointer(c)), + 1, // NumViews + uintptr(unsafe.Pointer(&target)), + uintptr(unsafe.Pointer(&depthStencilView)), + 0, 0, + ) + return target, depthStencilView +} + +func (c *DeviceContext) OMSetRenderTargets(target *RenderTargetView, depthStencil *DepthStencilView) { + syscall.Syscall6( + c.Vtbl.OMSetRenderTargets, + 4, + uintptr(unsafe.Pointer(c)), + 1, // NumViews + uintptr(unsafe.Pointer(&target)), + uintptr(unsafe.Pointer(depthStencil)), + 0, 0, + ) +} + +func (c *DeviceContext) Draw(count, start uint32) { + syscall.Syscall( + c.Vtbl.Draw, + 3, + uintptr(unsafe.Pointer(c)), + uintptr(count), + uintptr(start), + ) +} + +func (c *DeviceContext) DrawIndexed(count, start uint32, base int32) { + syscall.Syscall6( + c.Vtbl.DrawIndexed, + 4, + uintptr(unsafe.Pointer(c)), + uintptr(count), + uintptr(start), + uintptr(base), + 0, 0, + ) +} + +func (c *DeviceContext) Dispatch(x, y, z uint32) { + syscall.Syscall6( + c.Vtbl.Dispatch, + 4, + uintptr(unsafe.Pointer(c)), + uintptr(x), + uintptr(y), + uintptr(z), + 0, 0, + ) +} + +func (c *DeviceContext) OMSetBlendState(state *BlendState, factor *f32color.RGBA, sampleMask uint32) { + syscall.Syscall6( + c.Vtbl.OMSetBlendState, + 4, + uintptr(unsafe.Pointer(c)), + uintptr(unsafe.Pointer(state)), + uintptr(unsafe.Pointer(factor)), + uintptr(sampleMask), + 0, 0, + ) +} + +func (c *DeviceContext) OMSetDepthStencilState(state *DepthStencilState, stencilRef uint32) { + syscall.Syscall( + c.Vtbl.OMSetDepthStencilState, + 3, + uintptr(unsafe.Pointer(c)), + uintptr(unsafe.Pointer(state)), + uintptr(stencilRef), + ) +} + +func (d *IDXGIObject) GetParent(guid *GUID) (*IDXGIObject, error) { + var parent *IDXGIObject + r, _, _ := syscall.Syscall( + d.Vtbl.GetParent, + 3, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(guid)), + uintptr(unsafe.Pointer(&parent)), + ) + if r != 0 { + return nil, ErrorCode{Name: "IDXGIObjectGetParent", Code: uint32(r)} + } + return parent, nil +} + +func (d *IDXGIFactory) CreateSwapChain(device *IUnknown, desc *DXGI_SWAP_CHAIN_DESC) (*IDXGISwapChain, error) { + var swchain *IDXGISwapChain + r, _, _ := syscall.Syscall6( + d.Vtbl.CreateSwapChain, + 4, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(device)), + uintptr(unsafe.Pointer(desc)), + uintptr(unsafe.Pointer(&swchain)), + 0, 0, + ) + if r != 0 { + return nil, ErrorCode{Name: "IDXGIFactory", Code: uint32(r)} + } + return swchain, nil +} + +func (d *IDXGIDevice) GetAdapter() (*IDXGIAdapter, error) { + var adapter *IDXGIAdapter + r, _, _ := syscall.Syscall( + d.Vtbl.GetAdapter, + 2, + uintptr(unsafe.Pointer(d)), + uintptr(unsafe.Pointer(&adapter)), + 0, + ) + if r != 0 { + return nil, ErrorCode{Name: "IDXGIDeviceGetAdapter", Code: uint32(r)} + } + return adapter, nil +} + +func IUnknownQueryInterface(obj unsafe.Pointer, queryInterfaceMethod uintptr, guid *GUID) (*IUnknown, error) { + var ref *IUnknown + r, _, _ := syscall.Syscall( + queryInterfaceMethod, + 3, + uintptr(obj), + uintptr(unsafe.Pointer(guid)), + uintptr(unsafe.Pointer(&ref)), + ) + if r != 0 { + return nil, ErrorCode{Name: "IUnknownQueryInterface", Code: uint32(r)} + } + return ref, nil +} + +func IUnknownAddRef(obj unsafe.Pointer, addRefMethod uintptr) { + syscall.Syscall( + addRefMethod, + 1, + uintptr(obj), + 0, + 0, + ) +} + +func IUnknownRelease(obj unsafe.Pointer, releaseMethod uintptr) { + syscall.Syscall( + releaseMethod, + 1, + uintptr(obj), + 0, + 0, + ) +} + +func (e ErrorCode) Error() string { + return fmt.Sprintf("%s: %#x", e.Name, e.Code) +} + +func CreateSwapChain(dev *Device, hwnd windows.Handle) (*IDXGISwapChain, error) { + dxgiDev, err := IUnknownQueryInterface(unsafe.Pointer(dev), dev.Vtbl.QueryInterface, &IID_IDXGIDevice) + if err != nil { + return nil, fmt.Errorf("NewContext: %v", err) + } + adapter, err := (*IDXGIDevice)(unsafe.Pointer(dxgiDev)).GetAdapter() + IUnknownRelease(unsafe.Pointer(dxgiDev), dxgiDev.Vtbl.Release) + if err != nil { + return nil, fmt.Errorf("NewContext: %v", err) + } + dxgiFactory, err := (*IDXGIObject)(unsafe.Pointer(adapter)).GetParent(&IID_IDXGIFactory) + IUnknownRelease(unsafe.Pointer(adapter), adapter.Vtbl.Release) + if err != nil { + return nil, fmt.Errorf("NewContext: %v", err) + } + swchain, err := (*IDXGIFactory)(unsafe.Pointer(dxgiFactory)).CreateSwapChain( + (*IUnknown)(unsafe.Pointer(dev)), + &DXGI_SWAP_CHAIN_DESC{ + BufferDesc: DXGI_MODE_DESC{ + Format: DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, + }, + SampleDesc: DXGI_SAMPLE_DESC{ + Count: 1, + }, + BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT, + BufferCount: 1, + OutputWindow: hwnd, + Windowed: 1, + SwapEffect: DXGI_SWAP_EFFECT_DISCARD, + }, + ) + IUnknownRelease(unsafe.Pointer(dxgiFactory), dxgiFactory.Vtbl.Release) + if err != nil { + return nil, fmt.Errorf("NewContext: %v", err) + } + return swchain, nil +} + +func CreateDepthView(d *Device, width, height, depthBits int) (*DepthStencilView, error) { + depthTex, err := d.CreateTexture2D(&TEXTURE2D_DESC{ + Width: uint32(width), + Height: uint32(height), + MipLevels: 1, + ArraySize: 1, + Format: DXGI_FORMAT_D24_UNORM_S8_UINT, + SampleDesc: DXGI_SAMPLE_DESC{ + Count: 1, + Quality: 0, + }, + BindFlags: BIND_DEPTH_STENCIL, + }) + if err != nil { + return nil, err + } + depthView, err := d.CreateDepthStencilViewTEX2D( + (*Resource)(unsafe.Pointer(depthTex)), + &DEPTH_STENCIL_VIEW_DESC_TEX2D{ + Format: DXGI_FORMAT_D24_UNORM_S8_UINT, + ViewDimension: DSV_DIMENSION_TEXTURE2D, + }, + ) + IUnknownRelease(unsafe.Pointer(depthTex), depthTex.Vtbl.Release) + return depthView, err +} diff --git a/vendor/gioui.org/internal/egl/egl.go b/vendor/gioui.org/internal/egl/egl.go new file mode 100644 index 0000000..7d7b551 --- /dev/null +++ b/vendor/gioui.org/internal/egl/egl.go @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +//go:build linux || windows || freebsd || openbsd +// +build linux windows freebsd openbsd + +package egl + +import ( + "errors" + "fmt" + "runtime" + "strings" + + "gioui.org/gpu" +) + +type Context struct { + disp _EGLDisplay + eglCtx *eglContext + eglSurf _EGLSurface + width, height int +} + +type eglContext struct { + config _EGLConfig + ctx _EGLContext + visualID int + srgb bool + surfaceless bool +} + +var ( + nilEGLDisplay _EGLDisplay + nilEGLSurface _EGLSurface + nilEGLContext _EGLContext + nilEGLConfig _EGLConfig + EGL_DEFAULT_DISPLAY NativeDisplayType +) + +const ( + _EGL_ALPHA_SIZE = 0x3021 + _EGL_BLUE_SIZE = 0x3022 + _EGL_CONFIG_CAVEAT = 0x3027 + _EGL_CONTEXT_CLIENT_VERSION = 0x3098 + _EGL_DEPTH_SIZE = 0x3025 + _EGL_GL_COLORSPACE_KHR = 0x309d + _EGL_GL_COLORSPACE_SRGB_KHR = 0x3089 + _EGL_GREEN_SIZE = 0x3023 + _EGL_EXTENSIONS = 0x3055 + _EGL_NATIVE_VISUAL_ID = 0x302e + _EGL_NONE = 0x3038 + _EGL_OPENGL_ES2_BIT = 0x4 + _EGL_RED_SIZE = 0x3024 + _EGL_RENDERABLE_TYPE = 0x3040 + _EGL_SURFACE_TYPE = 0x3033 + _EGL_WINDOW_BIT = 0x4 +) + +func (c *Context) Release() { + c.ReleaseSurface() + if c.eglCtx != nil { + eglDestroyContext(c.disp, c.eglCtx.ctx) + c.eglCtx = nil + } + c.disp = nilEGLDisplay +} + +func (c *Context) Present() error { + if !eglSwapBuffers(c.disp, c.eglSurf) { + return fmt.Errorf("eglSwapBuffers failed (%x)", eglGetError()) + } + return nil +} + +func NewContext(disp NativeDisplayType) (*Context, error) { + if err := loadEGL(); err != nil { + return nil, err + } + eglDisp := eglGetDisplay(disp) + // eglGetDisplay can return EGL_NO_DISPLAY yet no error + // (EGL_SUCCESS), in which case a default EGL display might be + // available. + if eglDisp == nilEGLDisplay { + eglDisp = eglGetDisplay(EGL_DEFAULT_DISPLAY) + } + if eglDisp == nilEGLDisplay { + return nil, fmt.Errorf("eglGetDisplay failed: 0x%x", eglGetError()) + } + eglCtx, err := createContext(eglDisp) + if err != nil { + return nil, err + } + c := &Context{ + disp: eglDisp, + eglCtx: eglCtx, + } + return c, nil +} + +func (c *Context) RenderTarget() (gpu.RenderTarget, error) { + return gpu.OpenGLRenderTarget{}, nil +} + +func (c *Context) API() gpu.API { + return gpu.OpenGL{} +} + +func (c *Context) ReleaseSurface() { + if c.eglSurf == nilEGLSurface { + return + } + // Make sure any in-flight GL commands are complete. + eglWaitClient() + c.ReleaseCurrent() + eglDestroySurface(c.disp, c.eglSurf) + c.eglSurf = nilEGLSurface +} + +func (c *Context) VisualID() int { + return c.eglCtx.visualID +} + +func (c *Context) CreateSurface(win NativeWindowType, width, height int) error { + eglSurf, err := createSurface(c.disp, c.eglCtx, win) + c.eglSurf = eglSurf + c.width = width + c.height = height + return err +} + +func (c *Context) ReleaseCurrent() { + if c.disp != nilEGLDisplay { + eglMakeCurrent(c.disp, nilEGLSurface, nilEGLSurface, nilEGLContext) + } +} + +func (c *Context) MakeCurrent() error { + // OpenGL contexts are implicit and thread-local. Lock the OS thread. + runtime.LockOSThread() + + if c.eglSurf == nilEGLSurface && !c.eglCtx.surfaceless { + return errors.New("no surface created yet EGL_KHR_surfaceless_context is not supported") + } + if !eglMakeCurrent(c.disp, c.eglSurf, c.eglSurf, c.eglCtx.ctx) { + return fmt.Errorf("eglMakeCurrent error 0x%x", eglGetError()) + } + return nil +} + +func (c *Context) EnableVSync(enable bool) { + if enable { + eglSwapInterval(c.disp, 1) + } else { + eglSwapInterval(c.disp, 0) + } +} + +func hasExtension(exts []string, ext string) bool { + for _, e := range exts { + if ext == e { + return true + } + } + return false +} + +func createContext(disp _EGLDisplay) (*eglContext, error) { + major, minor, ret := eglInitialize(disp) + if !ret { + return nil, fmt.Errorf("eglInitialize failed: 0x%x", eglGetError()) + } + // sRGB framebuffer support on EGL 1.5 or if EGL_KHR_gl_colorspace is supported. + exts := strings.Split(eglQueryString(disp, _EGL_EXTENSIONS), " ") + srgb := major > 1 || minor >= 5 || hasExtension(exts, "EGL_KHR_gl_colorspace") + attribs := []_EGLint{ + _EGL_RENDERABLE_TYPE, _EGL_OPENGL_ES2_BIT, + _EGL_SURFACE_TYPE, _EGL_WINDOW_BIT, + _EGL_BLUE_SIZE, 8, + _EGL_GREEN_SIZE, 8, + _EGL_RED_SIZE, 8, + _EGL_CONFIG_CAVEAT, _EGL_NONE, + } + if srgb { + if runtime.GOOS == "linux" || runtime.GOOS == "android" { + // Some Mesa drivers crash if an sRGB framebuffer is requested without alpha. + // https://bugs.freedesktop.org/show_bug.cgi?id=107782. + // + // Also, some Android devices (Samsung S9) need alpha for sRGB to work. + attribs = append(attribs, _EGL_ALPHA_SIZE, 8) + } + } + attribs = append(attribs, _EGL_NONE) + eglCfg, ret := eglChooseConfig(disp, attribs) + if !ret { + return nil, fmt.Errorf("eglChooseConfig failed: 0x%x", eglGetError()) + } + if eglCfg == nilEGLConfig { + supportsNoCfg := hasExtension(exts, "EGL_KHR_no_config_context") + if !supportsNoCfg { + return nil, errors.New("eglChooseConfig returned no configs") + } + } + var visID _EGLint + if eglCfg != nilEGLConfig { + var ok bool + visID, ok = eglGetConfigAttrib(disp, eglCfg, _EGL_NATIVE_VISUAL_ID) + if !ok { + return nil, errors.New("newContext: eglGetConfigAttrib for _EGL_NATIVE_VISUAL_ID failed") + } + } + ctxAttribs := []_EGLint{ + _EGL_CONTEXT_CLIENT_VERSION, 3, + _EGL_NONE, + } + eglCtx := eglCreateContext(disp, eglCfg, nilEGLContext, ctxAttribs) + if eglCtx == nilEGLContext { + // Fall back to OpenGL ES 2 and rely on extensions. + ctxAttribs := []_EGLint{ + _EGL_CONTEXT_CLIENT_VERSION, 2, + _EGL_NONE, + } + eglCtx = eglCreateContext(disp, eglCfg, nilEGLContext, ctxAttribs) + if eglCtx == nilEGLContext { + return nil, fmt.Errorf("eglCreateContext failed: 0x%x", eglGetError()) + } + } + return &eglContext{ + config: _EGLConfig(eglCfg), + ctx: _EGLContext(eglCtx), + visualID: int(visID), + srgb: srgb, + surfaceless: hasExtension(exts, "EGL_KHR_surfaceless_context"), + }, nil +} + +func createSurface(disp _EGLDisplay, eglCtx *eglContext, win NativeWindowType) (_EGLSurface, error) { + var surfAttribs []_EGLint + if eglCtx.srgb { + surfAttribs = append(surfAttribs, _EGL_GL_COLORSPACE_KHR, _EGL_GL_COLORSPACE_SRGB_KHR) + } + surfAttribs = append(surfAttribs, _EGL_NONE) + eglSurf := eglCreateWindowSurface(disp, eglCtx.config, win, surfAttribs) + if eglSurf == nilEGLSurface && eglCtx.srgb { + // Try again without sRGB. + eglCtx.srgb = false + surfAttribs = []_EGLint{_EGL_NONE} + eglSurf = eglCreateWindowSurface(disp, eglCtx.config, win, surfAttribs) + } + if eglSurf == nilEGLSurface { + return nilEGLSurface, fmt.Errorf("newContext: eglCreateWindowSurface failed 0x%x (sRGB=%v)", eglGetError(), eglCtx.srgb) + } + return eglSurf, nil +} diff --git a/vendor/gioui.org/internal/egl/egl_unix.go b/vendor/gioui.org/internal/egl/egl_unix.go new file mode 100644 index 0000000..bd3efa5 --- /dev/null +++ b/vendor/gioui.org/internal/egl/egl_unix.go @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +//go:build linux || freebsd || openbsd +// +build linux freebsd openbsd + +package egl + +/* +#cgo linux,!android pkg-config: egl +#cgo freebsd openbsd android LDFLAGS: -lEGL +#cgo freebsd CFLAGS: -I/usr/local/include +#cgo freebsd LDFLAGS: -L/usr/local/lib +#cgo openbsd CFLAGS: -I/usr/X11R6/include +#cgo openbsd LDFLAGS: -L/usr/X11R6/lib +#cgo CFLAGS: -DEGL_NO_X11 + +#include <EGL/egl.h> +#include <EGL/eglext.h> +*/ +import "C" + +type ( + _EGLint = C.EGLint + _EGLDisplay = C.EGLDisplay + _EGLConfig = C.EGLConfig + _EGLContext = C.EGLContext + _EGLSurface = C.EGLSurface + NativeDisplayType = C.EGLNativeDisplayType + NativeWindowType = C.EGLNativeWindowType +) + +func loadEGL() error { + return nil +} + +func eglChooseConfig(disp _EGLDisplay, attribs []_EGLint) (_EGLConfig, bool) { + var cfg C.EGLConfig + var ncfg C.EGLint + if C.eglChooseConfig(disp, &attribs[0], &cfg, 1, &ncfg) != C.EGL_TRUE { + return nilEGLConfig, false + } + return _EGLConfig(cfg), true +} + +func eglCreateContext(disp _EGLDisplay, cfg _EGLConfig, shareCtx _EGLContext, attribs []_EGLint) _EGLContext { + ctx := C.eglCreateContext(disp, cfg, shareCtx, &attribs[0]) + return _EGLContext(ctx) +} + +func eglDestroySurface(disp _EGLDisplay, surf _EGLSurface) bool { + return C.eglDestroySurface(disp, surf) == C.EGL_TRUE +} + +func eglDestroyContext(disp _EGLDisplay, ctx _EGLContext) bool { + return C.eglDestroyContext(disp, ctx) == C.EGL_TRUE +} + +func eglGetConfigAttrib(disp _EGLDisplay, cfg _EGLConfig, attr _EGLint) (_EGLint, bool) { + var val _EGLint + ret := C.eglGetConfigAttrib(disp, cfg, attr, &val) + return val, ret == C.EGL_TRUE +} + +func eglGetError() _EGLint { + return C.eglGetError() +} + +func eglInitialize(disp _EGLDisplay) (_EGLint, _EGLint, bool) { + var maj, min _EGLint + ret := C.eglInitialize(disp, &maj, &min) + return maj, min, ret == C.EGL_TRUE +} + +func eglMakeCurrent(disp _EGLDisplay, draw, read _EGLSurface, ctx _EGLContext) bool { + return C.eglMakeCurrent(disp, draw, read, ctx) == C.EGL_TRUE +} + +func eglReleaseThread() bool { + return C.eglReleaseThread() == C.EGL_TRUE +} + +func eglSwapBuffers(disp _EGLDisplay, surf _EGLSurface) bool { + return C.eglSwapBuffers(disp, surf) == C.EGL_TRUE +} + +func eglSwapInterval(disp _EGLDisplay, interval _EGLint) bool { + return C.eglSwapInterval(disp, interval) == C.EGL_TRUE +} + +func eglTerminate(disp _EGLDisplay) bool { + return C.eglTerminate(disp) == C.EGL_TRUE +} + +func eglQueryString(disp _EGLDisplay, name _EGLint) string { + return C.GoString(C.eglQueryString(disp, name)) +} + +func eglGetDisplay(disp NativeDisplayType) _EGLDisplay { + return C.eglGetDisplay(disp) +} + +func eglCreateWindowSurface(disp _EGLDisplay, conf _EGLConfig, win NativeWindowType, attribs []_EGLint) _EGLSurface { + eglSurf := C.eglCreateWindowSurface(disp, conf, win, &attribs[0]) + return eglSurf +} + +func eglWaitClient() bool { + return C.eglWaitClient() == C.EGL_TRUE +} diff --git a/vendor/gioui.org/internal/egl/egl_windows.go b/vendor/gioui.org/internal/egl/egl_windows.go new file mode 100644 index 0000000..4433dd7 --- /dev/null +++ b/vendor/gioui.org/internal/egl/egl_windows.go @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +package egl + +import ( + "fmt" + "runtime" + "sync" + "unsafe" + + syscall "golang.org/x/sys/windows" + + "gioui.org/internal/gl" +) + +type ( + _EGLint int32 + _EGLDisplay uintptr + _EGLConfig uintptr + _EGLContext uintptr + _EGLSurface uintptr + NativeDisplayType uintptr + NativeWindowType uintptr +) + +var ( + libEGL = syscall.NewLazyDLL("libEGL.dll") + _eglChooseConfig = libEGL.NewProc("eglChooseConfig") + _eglCreateContext = libEGL.NewProc("eglCreateContext") + _eglCreateWindowSurface = libEGL.NewProc("eglCreateWindowSurface") + _eglDestroyContext = libEGL.NewProc("eglDestroyContext") + _eglDestroySurface = libEGL.NewProc("eglDestroySurface") + _eglGetConfigAttrib = libEGL.NewProc("eglGetConfigAttrib") + _eglGetDisplay = libEGL.NewProc("eglGetDisplay") + _eglGetError = libEGL.NewProc("eglGetError") + _eglInitialize = libEGL.NewProc("eglInitialize") + _eglMakeCurrent = libEGL.NewProc("eglMakeCurrent") + _eglReleaseThread = libEGL.NewProc("eglReleaseThread") + _eglSwapInterval = libEGL.NewProc("eglSwapInterval") + _eglSwapBuffers = libEGL.NewProc("eglSwapBuffers") + _eglTerminate = libEGL.NewProc("eglTerminate") + _eglQueryString = libEGL.NewProc("eglQueryString") + _eglWaitClient = libEGL.NewProc("eglWaitClient") +) + +var loadOnce sync.Once + +func loadEGL() error { + var err error + loadOnce.Do(func() { + err = loadDLLs() + }) + return err +} + +func loadDLLs() error { + if err := loadDLL(libEGL, "libEGL.dll"); err != nil { + return err + } + if err := loadDLL(gl.LibGLESv2, "libGLESv2.dll"); err != nil { + return err + } + // d3dcompiler_47.dll is needed internally for shader compilation to function. + return loadDLL(syscall.NewLazyDLL("d3dcompiler_47.dll"), "d3dcompiler_47.dll") +} + +func loadDLL(dll *syscall.LazyDLL, name string) error { + err := dll.Load() + if err != nil { + return fmt.Errorf("egl: failed to load %s: %v", name, err) + } + return nil +} + +func eglChooseConfig(disp _EGLDisplay, attribs []_EGLint) (_EGLConfig, bool) { + var cfg _EGLConfig + var ncfg _EGLint + a := &attribs[0] + r, _, _ := _eglChooseConfig.Call(uintptr(disp), uintptr(unsafe.Pointer(a)), uintptr(unsafe.Pointer(&cfg)), 1, uintptr(unsafe.Pointer(&ncfg))) + issue34474KeepAlive(a) + return cfg, r != 0 +} + +func eglCreateContext(disp _EGLDisplay, cfg _EGLConfig, shareCtx _EGLContext, attribs []_EGLint) _EGLContext { + a := &attribs[0] + c, _, _ := _eglCreateContext.Call(uintptr(disp), uintptr(cfg), uintptr(shareCtx), uintptr(unsafe.Pointer(a))) + issue34474KeepAlive(a) + return _EGLContext(c) +} + +func eglCreateWindowSurface(disp _EGLDisplay, cfg _EGLConfig, win NativeWindowType, attribs []_EGLint) _EGLSurface { + a := &attribs[0] + s, _, _ := _eglCreateWindowSurface.Call(uintptr(disp), uintptr(cfg), uintptr(win), uintptr(unsafe.Pointer(a))) + issue34474KeepAlive(a) + return _EGLSurface(s) +} + +func eglDestroySurface(disp _EGLDisplay, surf _EGLSurface) bool { + r, _, _ := _eglDestroySurface.Call(uintptr(disp), uintptr(surf)) + return r != 0 +} + +func eglDestroyContext(disp _EGLDisplay, ctx _EGLContext) bool { + r, _, _ := _eglDestroyContext.Call(uintptr(disp), uintptr(ctx)) + return r != 0 +} + +func eglGetConfigAttrib(disp _EGLDisplay, cfg _EGLConfig, attr _EGLint) (_EGLint, bool) { + var val uintptr + r, _, _ := _eglGetConfigAttrib.Call(uintptr(disp), uintptr(cfg), uintptr(attr), uintptr(unsafe.Pointer(&val))) + return _EGLint(val), r != 0 +} + +func eglGetDisplay(disp NativeDisplayType) _EGLDisplay { + d, _, _ := _eglGetDisplay.Call(uintptr(disp)) + return _EGLDisplay(d) +} + +func eglGetError() _EGLint { + e, _, _ := _eglGetError.Call() + return _EGLint(e) +} + +func eglInitialize(disp _EGLDisplay) (_EGLint, _EGLint, bool) { + var maj, min uintptr + r, _, _ := _eglInitialize.Call(uintptr(disp), uintptr(unsafe.Pointer(&maj)), uintptr(unsafe.Pointer(&min))) + return _EGLint(maj), _EGLint(min), r != 0 +} + +func eglMakeCurrent(disp _EGLDisplay, draw, read _EGLSurface, ctx _EGLContext) bool { + r, _, _ := _eglMakeCurrent.Call(uintptr(disp), uintptr(draw), uintptr(read), uintptr(ctx)) + return r != 0 +} + +func eglReleaseThread() bool { + r, _, _ := _eglReleaseThread.Call() + return r != 0 +} + +func eglSwapInterval(disp _EGLDisplay, interval _EGLint) bool { + r, _, _ := _eglSwapInterval.Call(uintptr(disp), uintptr(interval)) + return r != 0 +} + +func eglSwapBuffers(disp _EGLDisplay, surf _EGLSurface) bool { + r, _, _ := _eglSwapBuffers.Call(uintptr(disp), uintptr(surf)) + return r != 0 +} + +func eglTerminate(disp _EGLDisplay) bool { + r, _, _ := _eglTerminate.Call(uintptr(disp)) + return r != 0 +} + +func eglQueryString(disp _EGLDisplay, name _EGLint) string { + r, _, _ := _eglQueryString.Call(uintptr(disp), uintptr(name)) + return syscall.BytePtrToString((*byte)(unsafe.Pointer(r))) +} + +func eglWaitClient() bool { + r, _, _ := _eglWaitClient.Call() + return r != 0 +} + +// issue34474KeepAlive calls runtime.KeepAlive as a +// workaround for golang.org/issue/34474. +func issue34474KeepAlive(v interface{}) { + runtime.KeepAlive(v) +} diff --git a/vendor/gioui.org/internal/f32color/rgba.go b/vendor/gioui.org/internal/f32color/rgba.go index efaa1fb..eecf018 100644 --- a/vendor/gioui.org/internal/f32color/rgba.go +++ b/vendor/gioui.org/internal/f32color/rgba.go @@ -7,7 +7,7 @@ import ( "math" ) -// RGBA is a 32 bit floating point linear space color. +// RGBA is a 32 bit floating point linear premultiplied color space. type RGBA struct { R, G, B, A float32 } @@ -23,30 +23,90 @@ func (col RGBA) Float32() (r, g, b, a float32) { } // SRGBA converts from linear to sRGB color space. -func (col RGBA) SRGB() color.RGBA { - return color.RGBA{ - R: uint8(linearTosRGB(col.R)*255 + .5), - G: uint8(linearTosRGB(col.G)*255 + .5), - B: uint8(linearTosRGB(col.B)*255 + .5), +func (col RGBA) SRGB() color.NRGBA { + if col.A == 0 { + return color.NRGBA{} + } + return color.NRGBA{ + R: uint8(linearTosRGB(col.R/col.A)*255 + .5), + G: uint8(linearTosRGB(col.G/col.A)*255 + .5), + B: uint8(linearTosRGB(col.B/col.A)*255 + .5), A: uint8(col.A*255 + .5), } } +// Luminance calculates the relative luminance of a linear RGBA color. +// Normalized to 0 for black and 1 for white. +// +// See https://www.w3.org/TR/WCAG20/#relativeluminancedef for more details +func (col RGBA) Luminance() float32 { + return 0.2126*col.R + 0.7152*col.G + 0.0722*col.B +} + // Opaque returns the color without alpha component. func (col RGBA) Opaque() RGBA { col.A = 1.0 return col } -// RGBAFromSRGB converts from SRGBA to RGBA. -func RGBAFromSRGB(col color.RGBA) RGBA { - r, g, b, a := col.RGBA() +// LinearFromSRGB converts from col in the sRGB colorspace to RGBA. +func LinearFromSRGB(col color.NRGBA) RGBA { + af := float32(col.A) / 0xFF return RGBA{ - R: sRGBToLinear(float32(r) / 0xffff), - G: sRGBToLinear(float32(g) / 0xffff), - B: sRGBToLinear(float32(b) / 0xffff), - A: float32(a) / 0xFFFF, + R: sRGBToLinear(float32(col.R)/0xff) * af, + G: sRGBToLinear(float32(col.G)/0xff) * af, + B: sRGBToLinear(float32(col.B)/0xff) * af, + A: af, + } +} + +// NRGBAToRGBA converts from non-premultiplied sRGB color to premultiplied sRGB color. +// +// Each component in the result is `sRGBToLinear(c * alpha)`, where `c` +// is the linear color. +func NRGBAToRGBA(col color.NRGBA) color.RGBA { + if col.A == 0xFF { + return color.RGBA(col) + } + c := LinearFromSRGB(col) + return color.RGBA{ + R: uint8(linearTosRGB(c.R)*255 + .5), + G: uint8(linearTosRGB(c.G)*255 + .5), + B: uint8(linearTosRGB(c.B)*255 + .5), + A: col.A, + } +} + +// NRGBAToLinearRGBA converts from non-premultiplied sRGB color to premultiplied linear RGBA color. +// +// Each component in the result is `c * alpha`, where `c` is the linear color. +func NRGBAToLinearRGBA(col color.NRGBA) color.RGBA { + if col.A == 0xFF { + return color.RGBA(col) + } + c := LinearFromSRGB(col) + return color.RGBA{ + R: uint8(c.R*255 + .5), + G: uint8(c.G*255 + .5), + B: uint8(c.B*255 + .5), + A: col.A, + } +} + +// RGBAToNRGBA converts from premultiplied sRGB color to non-premultiplied sRGB color. +func RGBAToNRGBA(col color.RGBA) color.NRGBA { + if col.A == 0xFF { + return color.NRGBA(col) + } + + linear := RGBA{ + R: sRGBToLinear(float32(col.R) / 0xff), + G: sRGBToLinear(float32(col.G) / 0xff), + B: sRGBToLinear(float32(col.B) / 0xff), + A: float32(col.A) / 0xff, } + + return linear.SRGB() } // linearTosRGB transforms color value from linear to sRGB. @@ -73,3 +133,45 @@ func sRGBToLinear(c float32) float32 { return float32(math.Pow(float64((c+0.055)/1.055), 2.4)) } } + +// MulAlpha applies the alpha to the color. +func MulAlpha(c color.NRGBA, alpha uint8) color.NRGBA { + c.A = uint8(uint32(c.A) * uint32(alpha) / 0xFF) + return c +} + +// Disabled blends color towards the luminance and multiplies alpha. +// Blending towards luminance will desaturate the color. +// Multiplying alpha blends the color together more with the background. +func Disabled(c color.NRGBA) (d color.NRGBA) { + const r = 80 // blend ratio + lum := approxLuminance(c) + return color.NRGBA{ + R: byte((int(c.R)*r + int(lum)*(256-r)) / 256), + G: byte((int(c.G)*r + int(lum)*(256-r)) / 256), + B: byte((int(c.B)*r + int(lum)*(256-r)) / 256), + A: byte(int(c.A) * (128 + 32) / 256), + } +} + +// Hovered blends color towards a brighter color. +func Hovered(c color.NRGBA) (d color.NRGBA) { + const r = 0x20 // lighten ratio + return color.NRGBA{ + R: byte(255 - int(255-c.R)*(255-r)/256), + G: byte(255 - int(255-c.G)*(255-r)/256), + B: byte(255 - int(255-c.B)*(255-r)/256), + A: c.A, + } +} + +// approxLuminance is a fast approximate version of RGBA.Luminance. +func approxLuminance(c color.NRGBA) byte { + const ( + r = 13933 // 0.2126 * 256 * 256 + g = 46871 // 0.7152 * 256 * 256 + b = 4732 // 0.0722 * 256 * 256 + t = r + g + b + ) + return byte((r*int(c.R) + g*int(c.G) + b*int(c.B)) / t) +} diff --git a/vendor/gioui.org/internal/gl/gl.go b/vendor/gioui.org/internal/gl/gl.go new file mode 100644 index 0000000..a9e378a --- /dev/null +++ b/vendor/gioui.org/internal/gl/gl.go @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +package gl + +type ( + Attrib uint + Enum uint +) + +const ( + ACTIVE_TEXTURE = 0x84E0 + ALL_BARRIER_BITS = 0xffffffff + ARRAY_BUFFER = 0x8892 + ARRAY_BUFFER_BINDING = 0x8894 + BACK = 0x0405 + BLEND = 0xbe2 + BLEND_DST_RGB = 0x80C8 + BLEND_SRC_RGB = 0x80C9 + BLEND_DST_ALPHA = 0x80CA + BLEND_SRC_ALPHA = 0x80CB + CLAMP_TO_EDGE = 0x812f + COLOR_ATTACHMENT0 = 0x8ce0 + COLOR_BUFFER_BIT = 0x4000 + COLOR_CLEAR_VALUE = 0x0C22 + COMPILE_STATUS = 0x8b81 + COMPUTE_SHADER = 0x91B9 + CURRENT_PROGRAM = 0x8B8D + DEPTH_ATTACHMENT = 0x8d00 + DEPTH_BUFFER_BIT = 0x100 + DEPTH_CLEAR_VALUE = 0x0B73 + DEPTH_COMPONENT16 = 0x81a5 + DEPTH_COMPONENT24 = 0x81A6 + DEPTH_COMPONENT32F = 0x8CAC + DEPTH_FUNC = 0x0B74 + DEPTH_TEST = 0xb71 + DEPTH_WRITEMASK = 0x0B72 + DRAW_FRAMEBUFFER = 0x8CA9 + DST_COLOR = 0x306 + DYNAMIC_DRAW = 0x88E8 + DYNAMIC_READ = 0x88E9 + ELEMENT_ARRAY_BUFFER = 0x8893 + ELEMENT_ARRAY_BUFFER_BINDING = 0x8895 + EXTENSIONS = 0x1f03 + FALSE = 0 + FLOAT = 0x1406 + FRAGMENT_SHADER = 0x8b30 + FRAMEBUFFER = 0x8d40 + FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING = 0x8210 + FRAMEBUFFER_BINDING = 0x8ca6 + FRAMEBUFFER_COMPLETE = 0x8cd5 + FRAMEBUFFER_SRGB = 0x8db9 + HALF_FLOAT = 0x140b + HALF_FLOAT_OES = 0x8d61 + INFO_LOG_LENGTH = 0x8B84 + INVALID_INDEX = ^uint(0) + GREATER = 0x204 + GEQUAL = 0x206 + LINEAR = 0x2601 + LINK_STATUS = 0x8b82 + LUMINANCE = 0x1909 + MAP_READ_BIT = 0x0001 + MAX_TEXTURE_SIZE = 0xd33 + NEAREST = 0x2600 + NO_ERROR = 0x0 + NUM_EXTENSIONS = 0x821D + ONE = 0x1 + ONE_MINUS_SRC_ALPHA = 0x303 + PACK_ROW_LENGTH = 0x0D02 + PROGRAM_BINARY_LENGTH = 0x8741 + QUERY_RESULT = 0x8866 + QUERY_RESULT_AVAILABLE = 0x8867 + R16F = 0x822d + R8 = 0x8229 + READ_FRAMEBUFFER = 0x8ca8 + READ_FRAMEBUFFER_BINDING = 0x8CAA + READ_ONLY = 0x88B8 + READ_WRITE = 0x88BA + RED = 0x1903 + RENDERER = 0x1F01 + RENDERBUFFER = 0x8d41 + RENDERBUFFER_BINDING = 0x8ca7 + RENDERBUFFER_HEIGHT = 0x8d43 + RENDERBUFFER_WIDTH = 0x8d42 + RGB = 0x1907 + RGBA = 0x1908 + RGBA8 = 0x8058 + SHADER_STORAGE_BUFFER = 0x90D2 + SHADER_STORAGE_BUFFER_BINDING = 0x90D3 + SHORT = 0x1402 + SRGB = 0x8c40 + SRGB_ALPHA_EXT = 0x8c42 + SRGB8 = 0x8c41 + SRGB8_ALPHA8 = 0x8c43 + STATIC_DRAW = 0x88e4 + STENCIL_BUFFER_BIT = 0x00000400 + TEXTURE_2D = 0xde1 + TEXTURE_BINDING_2D = 0x8069 + TEXTURE_MAG_FILTER = 0x2800 + TEXTURE_MIN_FILTER = 0x2801 + TEXTURE_WRAP_S = 0x2802 + TEXTURE_WRAP_T = 0x2803 + TEXTURE0 = 0x84c0 + TEXTURE1 = 0x84c1 + TRIANGLE_STRIP = 0x5 + TRIANGLES = 0x4 + TRUE = 1 + UNIFORM_BUFFER = 0x8A11 + UNIFORM_BUFFER_BINDING = 0x8A28 + UNPACK_ALIGNMENT = 0xcf5 + UNPACK_ROW_LENGTH = 0x0CF2 + UNSIGNED_BYTE = 0x1401 + UNSIGNED_SHORT = 0x1403 + VIEWPORT = 0x0BA2 + VERSION = 0x1f02 + VERTEX_ARRAY_BINDING = 0x85B5 + VERTEX_SHADER = 0x8b31 + VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F + VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622 + VERTEX_ATTRIB_ARRAY_POINTER = 0x8645 + VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A + VERTEX_ATTRIB_ARRAY_SIZE = 0x8623 + VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624 + VERTEX_ATTRIB_ARRAY_TYPE = 0x8625 + WRITE_ONLY = 0x88B9 + ZERO = 0x0 + + // EXT_disjoint_timer_query + TIME_ELAPSED_EXT = 0x88BF + GPU_DISJOINT_EXT = 0x8FBB +) diff --git a/vendor/gioui.org/internal/gl/gl_js.go b/vendor/gioui.org/internal/gl/gl_js.go new file mode 100644 index 0000000..2c7976e --- /dev/null +++ b/vendor/gioui.org/internal/gl/gl_js.go @@ -0,0 +1,458 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +package gl + +import ( + "errors" + "strings" + "syscall/js" +) + +type Functions struct { + Ctx js.Value + EXT_disjoint_timer_query js.Value + EXT_disjoint_timer_query_webgl2 js.Value + + // Cached reference to the Uint8Array JS type. + uint8Array js.Value + + // Cached JS arrays. + arrayBuf js.Value + int32Buf js.Value + + isWebGL2 bool +} + +type Context js.Value + +func NewFunctions(ctx Context, forceES bool) (*Functions, error) { + f := &Functions{ + Ctx: js.Value(ctx), + uint8Array: js.Global().Get("Uint8Array"), + } + if err := f.Init(); err != nil { + return nil, err + } + return f, nil +} + +func (f *Functions) Init() error { + webgl2Class := js.Global().Get("WebGL2RenderingContext") + f.isWebGL2 = !webgl2Class.IsUndefined() && f.Ctx.InstanceOf(webgl2Class) + if !f.isWebGL2 { + f.EXT_disjoint_timer_query = f.getExtension("EXT_disjoint_timer_query") + if f.getExtension("OES_texture_half_float").IsNull() && f.getExtension("OES_texture_float").IsNull() { + return errors.New("gl: no support for neither OES_texture_half_float nor OES_texture_float") + } + if f.getExtension("EXT_sRGB").IsNull() { + return errors.New("gl: EXT_sRGB not supported") + } + } else { + // WebGL2 extensions. + f.EXT_disjoint_timer_query_webgl2 = f.getExtension("EXT_disjoint_timer_query_webgl2") + if f.getExtension("EXT_color_buffer_half_float").IsNull() && f.getExtension("EXT_color_buffer_float").IsNull() { + return errors.New("gl: no support for neither EXT_color_buffer_half_float nor EXT_color_buffer_float") + } + } + return nil +} + +func (f *Functions) getExtension(name string) js.Value { + return f.Ctx.Call("getExtension", name) +} + +func (f *Functions) ActiveTexture(t Enum) { + f.Ctx.Call("activeTexture", int(t)) +} +func (f *Functions) AttachShader(p Program, s Shader) { + f.Ctx.Call("attachShader", js.Value(p), js.Value(s)) +} +func (f *Functions) BeginQuery(target Enum, query Query) { + if !f.EXT_disjoint_timer_query_webgl2.IsNull() { + f.Ctx.Call("beginQuery", int(target), js.Value(query)) + } else { + f.EXT_disjoint_timer_query.Call("beginQueryEXT", int(target), js.Value(query)) + } +} +func (f *Functions) BindAttribLocation(p Program, a Attrib, name string) { + f.Ctx.Call("bindAttribLocation", js.Value(p), int(a), name) +} +func (f *Functions) BindBuffer(target Enum, b Buffer) { + f.Ctx.Call("bindBuffer", int(target), js.Value(b)) +} +func (f *Functions) BindBufferBase(target Enum, index int, b Buffer) { + f.Ctx.Call("bindBufferBase", int(target), index, js.Value(b)) +} +func (f *Functions) BindFramebuffer(target Enum, fb Framebuffer) { + f.Ctx.Call("bindFramebuffer", int(target), js.Value(fb)) +} +func (f *Functions) BindRenderbuffer(target Enum, rb Renderbuffer) { + f.Ctx.Call("bindRenderbuffer", int(target), js.Value(rb)) +} +func (f *Functions) BindTexture(target Enum, t Texture) { + f.Ctx.Call("bindTexture", int(target), js.Value(t)) +} +func (f *Functions) BindImageTexture(unit int, t Texture, level int, layered bool, layer int, access, format Enum) { + panic("not implemented") +} +func (f *Functions) BindVertexArray(a VertexArray) { + panic("not supported") +} +func (f *Functions) BlendEquation(mode Enum) { + f.Ctx.Call("blendEquation", int(mode)) +} +func (f *Functions) BlendFuncSeparate(srcRGB, dstRGB, srcA, dstA Enum) { + f.Ctx.Call("blendFunc", int(srcRGB), int(dstRGB), int(srcA), int(dstA)) +} +func (f *Functions) BufferData(target Enum, size int, usage Enum, data []byte) { + if data == nil { + f.Ctx.Call("bufferData", int(target), size, int(usage)) + } else { + if len(data) != size { + panic("size mismatch") + } + f.Ctx.Call("bufferData", int(target), f.byteArrayOf(data), int(usage)) + } +} +func (f *Functions) BufferSubData(target Enum, offset int, src []byte) { + f.Ctx.Call("bufferSubData", int(target), offset, f.byteArrayOf(src)) +} +func (f *Functions) CheckFramebufferStatus(target Enum) Enum { + return Enum(f.Ctx.Call("checkFramebufferStatus", int(target)).Int()) +} +func (f *Functions) Clear(mask Enum) { + f.Ctx.Call("clear", int(mask)) +} +func (f *Functions) ClearColor(red, green, blue, alpha float32) { + f.Ctx.Call("clearColor", red, green, blue, alpha) +} +func (f *Functions) ClearDepthf(d float32) { + f.Ctx.Call("clearDepth", d) +} +func (f *Functions) CompileShader(s Shader) { + f.Ctx.Call("compileShader", js.Value(s)) +} +func (f *Functions) CopyTexSubImage2D(target Enum, level, xoffset, yoffset, x, y, width, height int) { + f.Ctx.Call("copyTexSubImage2D", int(target), level, xoffset, yoffset, x, y, width, height) +} +func (f *Functions) CreateBuffer() Buffer { + return Buffer(f.Ctx.Call("createBuffer")) +} +func (f *Functions) CreateFramebuffer() Framebuffer { + return Framebuffer(f.Ctx.Call("createFramebuffer")) +} +func (f *Functions) CreateProgram() Program { + return Program(f.Ctx.Call("createProgram")) +} +func (f *Functions) CreateQuery() Query { + return Query(f.Ctx.Call("createQuery")) +} +func (f *Functions) CreateRenderbuffer() Renderbuffer { + return Renderbuffer(f.Ctx.Call("createRenderbuffer")) +} +func (f *Functions) CreateShader(ty Enum) Shader { + return Shader(f.Ctx.Call("createShader", int(ty))) +} +func (f *Functions) CreateTexture() Texture { + return Texture(f.Ctx.Call("createTexture")) +} +func (f *Functions) CreateVertexArray() VertexArray { + panic("not supported") +} +func (f *Functions) DeleteBuffer(v Buffer) { + f.Ctx.Call("deleteBuffer", js.Value(v)) +} +func (f *Functions) DeleteFramebuffer(v Framebuffer) { + f.Ctx.Call("deleteFramebuffer", js.Value(v)) +} +func (f *Functions) DeleteProgram(p Program) { + f.Ctx.Call("deleteProgram", js.Value(p)) +} +func (f *Functions) DeleteQuery(query Query) { + if !f.EXT_disjoint_timer_query_webgl2.IsNull() { + f.Ctx.Call("deleteQuery", js.Value(query)) + } else { + f.EXT_disjoint_timer_query.Call("deleteQueryEXT", js.Value(query)) + } +} +func (f *Functions) DeleteShader(s Shader) { + f.Ctx.Call("deleteShader", js.Value(s)) +} +func (f *Functions) DeleteRenderbuffer(v Renderbuffer) { + f.Ctx.Call("deleteRenderbuffer", js.Value(v)) +} +func (f *Functions) DeleteTexture(v Texture) { + f.Ctx.Call("deleteTexture", js.Value(v)) +} +func (f *Functions) DeleteVertexArray(a VertexArray) { + panic("not implemented") +} +func (f *Functions) DepthFunc(fn Enum) { + f.Ctx.Call("depthFunc", int(fn)) +} +func (f *Functions) DepthMask(mask bool) { + f.Ctx.Call("depthMask", mask) +} +func (f *Functions) DisableVertexAttribArray(a Attrib) { + f.Ctx.Call("disableVertexAttribArray", int(a)) +} +func (f *Functions) Disable(cap Enum) { + f.Ctx.Call("disable", int(cap)) +} +func (f *Functions) DrawArrays(mode Enum, first, count int) { + f.Ctx.Call("drawArrays", int(mode), first, count) +} +func (f *Functions) DrawElements(mode Enum, count int, ty Enum, offset int) { + f.Ctx.Call("drawElements", int(mode), count, int(ty), offset) +} +func (f *Functions) DispatchCompute(x, y, z int) { + panic("not implemented") +} +func (f *Functions) Enable(cap Enum) { + f.Ctx.Call("enable", int(cap)) +} +func (f *Functions) EnableVertexAttribArray(a Attrib) { + f.Ctx.Call("enableVertexAttribArray", int(a)) +} +func (f *Functions) EndQuery(target Enum) { + if !f.EXT_disjoint_timer_query_webgl2.IsNull() { + f.Ctx.Call("endQuery", int(target)) + } else { + f.EXT_disjoint_timer_query.Call("endQueryEXT", int(target)) + } +} +func (f *Functions) Finish() { + f.Ctx.Call("finish") +} +func (f *Functions) Flush() { + f.Ctx.Call("flush") +} +func (f *Functions) FramebufferRenderbuffer(target, attachment, renderbuffertarget Enum, renderbuffer Renderbuffer) { + f.Ctx.Call("framebufferRenderbuffer", int(target), int(attachment), int(renderbuffertarget), js.Value(renderbuffer)) +} +func (f *Functions) FramebufferTexture2D(target, attachment, texTarget Enum, t Texture, level int) { + f.Ctx.Call("framebufferTexture2D", int(target), int(attachment), int(texTarget), js.Value(t), level) +} +func (f *Functions) GetError() Enum { + // Avoid slow getError calls. See gio#179. + return 0 +} +func (f *Functions) GetRenderbufferParameteri(target, pname Enum) int { + return paramVal(f.Ctx.Call("getRenderbufferParameteri", int(pname))) +} +func (f *Functions) GetFramebufferAttachmentParameteri(target, attachment, pname Enum) int { + if !f.isWebGL2 && pname == FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING { + // FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING is only available on WebGL 2 + return LINEAR + } + return paramVal(f.Ctx.Call("getFramebufferAttachmentParameter", int(target), int(attachment), int(pname))) +} +func (f *Functions) GetBinding(pname Enum) Object { + obj := f.Ctx.Call("getParameter", int(pname)) + if !obj.Truthy() { + return Object{} + } + return Object(obj) +} +func (f *Functions) GetBindingi(pname Enum, idx int) Object { + obj := f.Ctx.Call("getIndexedParameter", int(pname), idx) + if !obj.Truthy() { + return Object{} + } + return Object(obj) +} +func (f *Functions) GetInteger(pname Enum) int { + if !f.isWebGL2 { + switch pname { + case PACK_ROW_LENGTH, UNPACK_ROW_LENGTH: + return 0 // PACK_ROW_LENGTH and UNPACK_ROW_LENGTH is only available on WebGL 2 + } + } + return paramVal(f.Ctx.Call("getParameter", int(pname))) +} +func (f *Functions) GetFloat(pname Enum) float32 { + return float32(f.Ctx.Call("getParameter", int(pname)).Float()) +} +func (f *Functions) GetInteger4(pname Enum) [4]int { + arr := f.Ctx.Call("getParameter", int(pname)) + var res [4]int + for i := range res { + res[i] = arr.Index(i).Int() + } + return res +} +func (f *Functions) GetFloat4(pname Enum) [4]float32 { + arr := f.Ctx.Call("getParameter", int(pname)) + var res [4]float32 + for i := range res { + res[i] = float32(arr.Index(i).Float()) + } + return res +} +func (f *Functions) GetProgrami(p Program, pname Enum) int { + return paramVal(f.Ctx.Call("getProgramParameter", js.Value(p), int(pname))) +} +func (f *Functions) GetProgramInfoLog(p Program) string { + return f.Ctx.Call("getProgramInfoLog", js.Value(p)).String() +} +func (f *Functions) GetQueryObjectuiv(query Query, pname Enum) uint { + if !f.EXT_disjoint_timer_query_webgl2.IsNull() { + return uint(paramVal(f.Ctx.Call("getQueryParameter", js.Value(query), int(pname)))) + } else { + return uint(paramVal(f.EXT_disjoint_timer_query.Call("getQueryObjectEXT", js.Value(query), int(pname)))) + } +} +func (f *Functions) GetShaderi(s Shader, pname Enum) int { + return paramVal(f.Ctx.Call("getShaderParameter", js.Value(s), int(pname))) +} +func (f *Functions) GetShaderInfoLog(s Shader) string { + return f.Ctx.Call("getShaderInfoLog", js.Value(s)).String() +} +func (f *Functions) GetString(pname Enum) string { + switch pname { + case EXTENSIONS: + extsjs := f.Ctx.Call("getSupportedExtensions") + var exts []string + for i := 0; i < extsjs.Length(); i++ { + exts = append(exts, "GL_"+extsjs.Index(i).String()) + } + return strings.Join(exts, " ") + default: + return f.Ctx.Call("getParameter", int(pname)).String() + } +} +func (f *Functions) GetUniformBlockIndex(p Program, name string) uint { + return uint(paramVal(f.Ctx.Call("getUniformBlockIndex", js.Value(p), name))) +} +func (f *Functions) GetUniformLocation(p Program, name string) Uniform { + return Uniform(f.Ctx.Call("getUniformLocation", js.Value(p), name)) +} +func (f *Functions) GetVertexAttrib(index int, pname Enum) int { + return paramVal(f.Ctx.Call("getVertexAttrib", index, int(pname))) +} +func (f *Functions) GetVertexAttribBinding(index int, pname Enum) Object { + obj := f.Ctx.Call("getVertexAttrib", index, int(pname)) + if !obj.Truthy() { + return Object{} + } + return Object(obj) +} +func (f *Functions) GetVertexAttribPointer(index int, pname Enum) uintptr { + return uintptr(f.Ctx.Call("getVertexAttribOffset", index, int(pname)).Int()) +} +func (f *Functions) InvalidateFramebuffer(target, attachment Enum) { + fn := f.Ctx.Get("invalidateFramebuffer") + if !fn.IsUndefined() { + if f.int32Buf.IsUndefined() { + f.int32Buf = js.Global().Get("Int32Array").New(1) + } + f.int32Buf.SetIndex(0, int32(attachment)) + f.Ctx.Call("invalidateFramebuffer", int(target), f.int32Buf) + } +} +func (f *Functions) IsEnabled(cap Enum) bool { + return f.Ctx.Call("isEnabled", int(cap)).Truthy() +} +func (f *Functions) LinkProgram(p Program) { + f.Ctx.Call("linkProgram", js.Value(p)) +} +func (f *Functions) PixelStorei(pname Enum, param int) { + f.Ctx.Call("pixelStorei", int(pname), param) +} +func (f *Functions) MemoryBarrier(barriers Enum) { + panic("not implemented") +} +func (f *Functions) MapBufferRange(target Enum, offset, length int, access Enum) []byte { + panic("not implemented") +} +func (f *Functions) RenderbufferStorage(target, internalformat Enum, width, height int) { + f.Ctx.Call("renderbufferStorage", int(target), int(internalformat), width, height) +} +func (f *Functions) ReadPixels(x, y, width, height int, format, ty Enum, data []byte) { + ba := f.byteArrayOf(data) + f.Ctx.Call("readPixels", x, y, width, height, int(format), int(ty), ba) + js.CopyBytesToGo(data, ba) +} +func (f *Functions) Scissor(x, y, width, height int32) { + f.Ctx.Call("scissor", x, y, width, height) +} +func (f *Functions) ShaderSource(s Shader, src string) { + f.Ctx.Call("shaderSource", js.Value(s), src) +} +func (f *Functions) TexImage2D(target Enum, level int, internalFormat Enum, width, height int, format, ty Enum) { + f.Ctx.Call("texImage2D", int(target), int(level), int(internalFormat), int(width), int(height), 0, int(format), int(ty), nil) +} +func (f *Functions) TexStorage2D(target Enum, levels int, internalFormat Enum, width, height int) { + f.Ctx.Call("texStorage2D", int(target), levels, int(internalFormat), width, height) +} +func (f *Functions) TexSubImage2D(target Enum, level int, x, y, width, height int, format, ty Enum, data []byte) { + f.Ctx.Call("texSubImage2D", int(target), level, x, y, width, height, int(format), int(ty), f.byteArrayOf(data)) +} +func (f *Functions) TexParameteri(target, pname Enum, param int) { + f.Ctx.Call("texParameteri", int(target), int(pname), int(param)) +} +func (f *Functions) UniformBlockBinding(p Program, uniformBlockIndex uint, uniformBlockBinding uint) { + f.Ctx.Call("uniformBlockBinding", js.Value(p), int(uniformBlockIndex), int(uniformBlockBinding)) +} +func (f *Functions) Uniform1f(dst Uniform, v float32) { + f.Ctx.Call("uniform1f", js.Value(dst), v) +} +func (f *Functions) Uniform1i(dst Uniform, v int) { + f.Ctx.Call("uniform1i", js.Value(dst), v) +} +func (f *Functions) Uniform2f(dst Uniform, v0, v1 float32) { + f.Ctx.Call("uniform2f", js.Value(dst), v0, v1) +} +func (f *Functions) Uniform3f(dst Uniform, v0, v1, v2 float32) { + f.Ctx.Call("uniform3f", js.Value(dst), v0, v1, v2) +} +func (f *Functions) Uniform4f(dst Uniform, v0, v1, v2, v3 float32) { + f.Ctx.Call("uniform4f", js.Value(dst), v0, v1, v2, v3) +} +func (f *Functions) UseProgram(p Program) { + f.Ctx.Call("useProgram", js.Value(p)) +} +func (f *Functions) UnmapBuffer(target Enum) bool { + panic("not implemented") +} +func (f *Functions) VertexAttribPointer(dst Attrib, size int, ty Enum, normalized bool, stride, offset int) { + f.Ctx.Call("vertexAttribPointer", int(dst), size, int(ty), normalized, stride, offset) +} +func (f *Functions) Viewport(x, y, width, height int) { + f.Ctx.Call("viewport", x, y, width, height) +} + +func (f *Functions) byteArrayOf(data []byte) js.Value { + if len(data) == 0 { + return js.Null() + } + f.resizeByteBuffer(len(data)) + ba := f.uint8Array.New(f.arrayBuf, int(0), int(len(data))) + js.CopyBytesToJS(ba, data) + return ba +} + +func (f *Functions) resizeByteBuffer(n int) { + if n == 0 { + return + } + if !f.arrayBuf.IsUndefined() && f.arrayBuf.Length() >= n { + return + } + f.arrayBuf = js.Global().Get("ArrayBuffer").New(n) +} + +func paramVal(v js.Value) int { + switch v.Type() { + case js.TypeBoolean: + if b := v.Bool(); b { + return 1 + } else { + return 0 + } + case js.TypeNumber: + return v.Int() + default: + panic("unknown parameter type") + } +} diff --git a/vendor/gioui.org/internal/gl/gl_unix.go b/vendor/gioui.org/internal/gl/gl_unix.go new file mode 100644 index 0000000..f223ced --- /dev/null +++ b/vendor/gioui.org/internal/gl/gl_unix.go @@ -0,0 +1,1222 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +//go:build darwin || linux || freebsd || openbsd +// +build darwin linux freebsd openbsd + +package gl + +import ( + "fmt" + "runtime" + "strings" + "unsafe" +) + +/* +#cgo CFLAGS: -Werror +#cgo linux freebsd LDFLAGS: -ldl + +#include <stdint.h> +#include <stdlib.h> +#include <sys/types.h> +#define __USE_GNU +#include <dlfcn.h> + +typedef unsigned int GLenum; +typedef unsigned int GLuint; +typedef char GLchar; +typedef float GLfloat; +typedef ssize_t GLsizeiptr; +typedef intptr_t GLintptr; +typedef unsigned int GLbitfield; +typedef int GLint; +typedef unsigned char GLboolean; +typedef int GLsizei; +typedef uint8_t GLubyte; + +typedef struct { + void (*glActiveTexture)(GLenum texture); + void (*glAttachShader)(GLuint program, GLuint shader); + void (*glBindAttribLocation)(GLuint program, GLuint index, const GLchar *name); + void (*glBindBuffer)(GLenum target, GLuint buffer); + void (*glBindFramebuffer)(GLenum target, GLuint framebuffer); + void (*glBindRenderbuffer)(GLenum target, GLuint renderbuffer); + void (*glBindTexture)(GLenum target, GLuint texture); + void (*glBlendEquation)(GLenum mode); + void (*glBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcA, GLenum dstA); + void (*glBufferData)(GLenum target, GLsizeiptr size, const void *data, GLenum usage); + void (*glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data); + GLenum (*glCheckFramebufferStatus)(GLenum target); + void (*glClear)(GLbitfield mask); + void (*glClearColor)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); + void (*glClearDepthf)(GLfloat d); + void (*glCompileShader)(GLuint shader); + void (*glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); + GLuint (*glCreateProgram)(void); + GLuint (*glCreateShader)(GLenum type); + void (*glDeleteBuffers)(GLsizei n, const GLuint *buffers); + void (*glDeleteFramebuffers)(GLsizei n, const GLuint *framebuffers); + void (*glDeleteProgram)(GLuint program); + void (*glDeleteRenderbuffers)(GLsizei n, const GLuint *renderbuffers); + void (*glDeleteShader)(GLuint shader); + void (*glDeleteTextures)(GLsizei n, const GLuint *textures); + void (*glDepthFunc)(GLenum func); + void (*glDepthMask)(GLboolean flag); + void (*glDisable)(GLenum cap); + void (*glDisableVertexAttribArray)(GLuint index); + void (*glDrawArrays)(GLenum mode, GLint first, GLsizei count); + void (*glDrawElements)(GLenum mode, GLsizei count, GLenum type, const void *indices); + void (*glEnable)(GLenum cap); + void (*glEnableVertexAttribArray)(GLuint index); + void (*glFinish)(void); + void (*glFlush)(void); + void (*glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); + void (*glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); + void (*glGenBuffers)(GLsizei n, GLuint *buffers); + void (*glGenFramebuffers)(GLsizei n, GLuint *framebuffers); + void (*glGenRenderbuffers)(GLsizei n, GLuint *renderbuffers); + void (*glGenTextures)(GLsizei n, GLuint *textures); + GLenum (*glGetError)(void); + void (*glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint *params); + void (*glGetFloatv)(GLenum pname, GLfloat *data); + void (*glGetIntegerv)(GLenum pname, GLint *data); + void (*glGetIntegeri_v)(GLenum pname, GLuint idx, GLint *data); + void (*glGetProgramiv)(GLuint program, GLenum pname, GLint *params); + void (*glGetProgramInfoLog)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); + void (*glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint *params); + void (*glGetShaderiv)(GLuint shader, GLenum pname, GLint *params); + void (*glGetShaderInfoLog)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); + const GLubyte *(*glGetString)(GLenum name); + GLint (*glGetUniformLocation)(GLuint program, const GLchar *name); + void (*glGetVertexAttribiv)(GLuint index, GLenum pname, GLint *params); + void (*glGetVertexAttribPointerv)(GLuint index, GLenum pname, void **params); + GLboolean (*glIsEnabled)(GLenum cap); + void (*glLinkProgram)(GLuint program); + void (*glPixelStorei)(GLenum pname, GLint param); + void (*glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); + void (*glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); + void (*glScissor)(GLint x, GLint y, GLsizei width, GLsizei height); + void (*glShaderSource)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); + void (*glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); + void (*glTexParameteri)(GLenum target, GLenum pname, GLint param); + void (*glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); + void (*glUniform1f)(GLint location, GLfloat v0); + void (*glUniform1i)(GLint location, GLint v0); + void (*glUniform2f)(GLint location, GLfloat v0, GLfloat v1); + void (*glUniform3f)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); + void (*glUniform4f)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); + void (*glUseProgram)(GLuint program); + void (*glVertexAttribPointer)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); + void (*glViewport)(GLint x, GLint y, GLsizei width, GLsizei height); + + void (*glBindVertexArray)(GLuint array); + void (*glBindBufferBase)(GLenum target, GLuint index, GLuint buffer); + GLuint (*glGetUniformBlockIndex)(GLuint program, const GLchar *uniformBlockName); + void (*glUniformBlockBinding)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); + void (*glInvalidateFramebuffer)(GLenum target, GLsizei numAttachments, const GLenum *attachments); + void (*glBeginQuery)(GLenum target, GLuint id); + void (*glDeleteQueries)(GLsizei n, const GLuint *ids); + void (*glDeleteVertexArrays)(GLsizei n, const GLuint *ids); + void (*glEndQuery)(GLenum target); + void (*glGenQueries)(GLsizei n, GLuint *ids); + void (*glGenVertexArrays)(GLsizei n, GLuint *ids); + void (*glGetProgramBinary)(GLuint program, GLsizei bufsize, GLsizei *length, GLenum *binaryFormat, void *binary); + void (*glGetQueryObjectuiv)(GLuint id, GLenum pname, GLuint *params); + const GLubyte* (*glGetStringi)(GLenum name, GLuint index); + void (*glDispatchCompute)(GLuint x, GLuint y, GLuint z); + void (*glMemoryBarrier)(GLbitfield barriers); + void* (*glMapBufferRange)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); + GLboolean (*glUnmapBuffer)(GLenum target); + void (*glBindImageTexture)(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); + void (*glTexStorage2D)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); + void (*glBlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +} glFunctions; + +static void glActiveTexture(glFunctions *f, GLenum texture) { + f->glActiveTexture(texture); +} + +static void glAttachShader(glFunctions *f, GLuint program, GLuint shader) { + f->glAttachShader(program, shader); +} + +static void glBindAttribLocation(glFunctions *f, GLuint program, GLuint index, const GLchar *name) { + f->glBindAttribLocation(program, index, name); +} + +static void glBindBuffer(glFunctions *f, GLenum target, GLuint buffer) { + f->glBindBuffer(target, buffer); +} + +static void glBindFramebuffer(glFunctions *f, GLenum target, GLuint framebuffer) { + f->glBindFramebuffer(target, framebuffer); +} + +static void glBindRenderbuffer(glFunctions *f, GLenum target, GLuint renderbuffer) { + f->glBindRenderbuffer(target, renderbuffer); +} + +static void glBindTexture(glFunctions *f, GLenum target, GLuint texture) { + f->glBindTexture(target, texture); +} + +static void glBindVertexArray(glFunctions *f, GLuint array) { + f->glBindVertexArray(array); +} + +static void glBlendEquation(glFunctions *f, GLenum mode) { + f->glBlendEquation(mode); +} + +static void glBlendFuncSeparate(glFunctions *f, GLenum srcRGB, GLenum dstRGB, GLenum srcA, GLenum dstA) { + f->glBlendFuncSeparate(srcRGB, dstRGB, srcA, dstA); +} + +static void glBufferData(glFunctions *f, GLenum target, GLsizeiptr size, const void *data, GLenum usage) { + f->glBufferData(target, size, data, usage); +} + +static void glBufferSubData(glFunctions *f, GLenum target, GLintptr offset, GLsizeiptr size, const void *data) { + f->glBufferSubData(target, offset, size, data); +} + +static GLenum glCheckFramebufferStatus(glFunctions *f, GLenum target) { + return f->glCheckFramebufferStatus(target); +} + +static void glClear(glFunctions *f, GLbitfield mask) { + f->glClear(mask); +} + +static void glClearColor(glFunctions *f, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { + f->glClearColor(red, green, blue, alpha); +} + +static void glClearDepthf(glFunctions *f, GLfloat d) { + f->glClearDepthf(d); +} + +static void glCompileShader(glFunctions *f, GLuint shader) { + f->glCompileShader(shader); +} + +static void glCopyTexSubImage2D(glFunctions *f, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { + f->glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); +} + +static GLuint glCreateProgram(glFunctions *f) { + return f->glCreateProgram(); +} + +static GLuint glCreateShader(glFunctions *f, GLenum type) { + return f->glCreateShader(type); +} + +static void glDeleteBuffers(glFunctions *f, GLsizei n, const GLuint *buffers) { + f->glDeleteBuffers(n, buffers); +} + +static void glDeleteFramebuffers(glFunctions *f, GLsizei n, const GLuint *framebuffers) { + f->glDeleteFramebuffers(n, framebuffers); +} + +static void glDeleteProgram(glFunctions *f, GLuint program) { + f->glDeleteProgram(program); +} + +static void glDeleteRenderbuffers(glFunctions *f, GLsizei n, const GLuint *renderbuffers) { + f->glDeleteRenderbuffers(n, renderbuffers); +} + +static void glDeleteShader(glFunctions *f, GLuint shader) { + f->glDeleteShader(shader); +} + +static void glDeleteTextures(glFunctions *f, GLsizei n, const GLuint *textures) { + f->glDeleteTextures(n, textures); +} + +static void glDepthFunc(glFunctions *f, GLenum func) { + f->glDepthFunc(func); +} + +static void glDepthMask(glFunctions *f, GLboolean flag) { + f->glDepthMask(flag); +} + +static void glDisable(glFunctions *f, GLenum cap) { + f->glDisable(cap); +} + +static void glDisableVertexAttribArray(glFunctions *f, GLuint index) { + f->glDisableVertexAttribArray(index); +} + +static void glDrawArrays(glFunctions *f, GLenum mode, GLint first, GLsizei count) { + f->glDrawArrays(mode, first, count); +} + +// offset is defined as an uintptr_t to omit Cgo pointer checks. +static void glDrawElements(glFunctions *f, GLenum mode, GLsizei count, GLenum type, const uintptr_t offset) { + f->glDrawElements(mode, count, type, (const void *)offset); +} + +static void glEnable(glFunctions *f, GLenum cap) { + f->glEnable(cap); +} + +static void glEnableVertexAttribArray(glFunctions *f, GLuint index) { + f->glEnableVertexAttribArray(index); +} + +static void glFinish(glFunctions *f) { + f->glFinish(); +} + +static void glFlush(glFunctions *f) { + f->glFlush(); +} + +static void glFramebufferRenderbuffer(glFunctions *f, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { + f->glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); +} + +static void glFramebufferTexture2D(glFunctions *f, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { + f->glFramebufferTexture2D(target, attachment, textarget, texture, level); +} + +static void glGenBuffers(glFunctions *f, GLsizei n, GLuint *buffers) { + f->glGenBuffers(n, buffers); +} + +static void glGenFramebuffers(glFunctions *f, GLsizei n, GLuint *framebuffers) { + f->glGenFramebuffers(n, framebuffers); +} + +static void glGenRenderbuffers(glFunctions *f, GLsizei n, GLuint *renderbuffers) { + f->glGenRenderbuffers(n, renderbuffers); +} + +static void glGenTextures(glFunctions *f, GLsizei n, GLuint *textures) { + f->glGenTextures(n, textures); +} + +static GLenum glGetError(glFunctions *f) { + return f->glGetError(); +} + +static void glGetFramebufferAttachmentParameteriv(glFunctions *f, GLenum target, GLenum attachment, GLenum pname, GLint *params) { + f->glGetFramebufferAttachmentParameteriv(target, attachment, pname, params); +} + +static void glGetIntegerv(glFunctions *f, GLenum pname, GLint *data) { + f->glGetIntegerv(pname, data); +} + +static void glGetFloatv(glFunctions *f, GLenum pname, GLfloat *data) { + f->glGetFloatv(pname, data); +} + +static void glGetIntegeri_v(glFunctions *f, GLenum pname, GLuint idx, GLint *data) { + f->glGetIntegeri_v(pname, idx, data); +} + +static void glGetProgramiv(glFunctions *f, GLuint program, GLenum pname, GLint *params) { + f->glGetProgramiv(program, pname, params); +} + +static void glGetProgramInfoLog(glFunctions *f, GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { + f->glGetProgramInfoLog(program, bufSize, length, infoLog); +} + +static void glGetRenderbufferParameteriv(glFunctions *f, GLenum target, GLenum pname, GLint *params) { + f->glGetRenderbufferParameteriv(target, pname, params); +} + +static void glGetShaderiv(glFunctions *f, GLuint shader, GLenum pname, GLint *params) { + f->glGetShaderiv(shader, pname, params); +} + +static void glGetShaderInfoLog(glFunctions *f, GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { + f->glGetShaderInfoLog(shader, bufSize, length, infoLog); +} + +static const GLubyte *glGetString(glFunctions *f, GLenum name) { + return f->glGetString(name); +} + +static GLint glGetUniformLocation(glFunctions *f, GLuint program, const GLchar *name) { + return f->glGetUniformLocation(program, name); +} + +static void glGetVertexAttribiv(glFunctions *f, GLuint index, GLenum pname, GLint *data) { + f->glGetVertexAttribiv(index, pname, data); +} + +// Return uintptr_t to avoid Cgo pointer check. +static uintptr_t glGetVertexAttribPointerv(glFunctions *f, GLuint index, GLenum pname) { + void *ptrs; + f->glGetVertexAttribPointerv(index, pname, &ptrs); + return (uintptr_t)ptrs; +} + +static GLboolean glIsEnabled(glFunctions *f, GLenum cap) { + return f->glIsEnabled(cap); +} + +static void glLinkProgram(glFunctions *f, GLuint program) { + f->glLinkProgram(program); +} + +static void glPixelStorei(glFunctions *f, GLenum pname, GLint param) { + f->glPixelStorei(pname, param); +} + +static void glReadPixels(glFunctions *f, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) { + f->glReadPixels(x, y, width, height, format, type, pixels); +} + +static void glRenderbufferStorage(glFunctions *f, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { + f->glRenderbufferStorage(target, internalformat, width, height); +} + +static void glScissor(glFunctions *f, GLint x, GLint y, GLsizei width, GLsizei height) { + f->glScissor(x, y, width, height); +} + +static void glShaderSource(glFunctions *f, GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) { + f->glShaderSource(shader, count, string, length); +} + +static void glTexImage2D(glFunctions *f, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) { + f->glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); +} + +static void glTexParameteri(glFunctions *f, GLenum target, GLenum pname, GLint param) { + f->glTexParameteri(target, pname, param); +} + +static void glTexSubImage2D(glFunctions *f, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) { + f->glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); +} + +static void glUniform1f(glFunctions *f, GLint location, GLfloat v0) { + f->glUniform1f(location, v0); +} + +static void glUniform1i(glFunctions *f, GLint location, GLint v0) { + f->glUniform1i(location, v0); +} + +static void glUniform2f(glFunctions *f, GLint location, GLfloat v0, GLfloat v1) { + f->glUniform2f(location, v0, v1); +} + +static void glUniform3f(glFunctions *f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { + f->glUniform3f(location, v0, v1, v2); +} + +static void glUniform4f(glFunctions *f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { + f->glUniform4f(location, v0, v1, v2, v3); +} + +static void glUseProgram(glFunctions *f, GLuint program) { + f->glUseProgram(program); +} + +// offset is defined as an uintptr_t to omit Cgo pointer checks. +static void glVertexAttribPointer(glFunctions *f, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, uintptr_t offset) { + f->glVertexAttribPointer(index, size, type, normalized, stride, (const void *)offset); +} + +static void glViewport(glFunctions *f, GLint x, GLint y, GLsizei width, GLsizei height) { + f->glViewport(x, y, width, height); +} + +static void glBindBufferBase(glFunctions *f, GLenum target, GLuint index, GLuint buffer) { + f->glBindBufferBase(target, index, buffer); +} + +static void glUniformBlockBinding(glFunctions *f, GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) { + f->glUniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding); +} + +static GLuint glGetUniformBlockIndex(glFunctions *f, GLuint program, const GLchar *uniformBlockName) { + return f->glGetUniformBlockIndex(program, uniformBlockName); +} + +static void glInvalidateFramebuffer(glFunctions *f, GLenum target, GLenum attachment) { + // Framebuffer invalidation is just a hint and can safely be ignored. + if (f->glInvalidateFramebuffer != NULL) { + f->glInvalidateFramebuffer(target, 1, &attachment); + } +} + +static void glBeginQuery(glFunctions *f, GLenum target, GLenum attachment) { + f->glBeginQuery(target, attachment); +} + +static void glDeleteQueries(glFunctions *f, GLsizei n, const GLuint *ids) { + f->glDeleteQueries(n, ids); +} + +static void glDeleteVertexArrays(glFunctions *f, GLsizei n, const GLuint *ids) { + f->glDeleteVertexArrays(n, ids); +} + +static void glEndQuery(glFunctions *f, GLenum target) { + f->glEndQuery(target); +} + +static const GLubyte* glGetStringi(glFunctions *f, GLenum name, GLuint index) { + return f->glGetStringi(name, index); +} + +static void glGenQueries(glFunctions *f, GLsizei n, GLuint *ids) { + f->glGenQueries(n, ids); +} + +static void glGenVertexArrays(glFunctions *f, GLsizei n, GLuint *ids) { + f->glGenVertexArrays(n, ids); +} + +static void glGetProgramBinary(glFunctions *f, GLuint program, GLsizei bufsize, GLsizei *length, GLenum *binaryFormat, void *binary) { + f->glGetProgramBinary(program, bufsize, length, binaryFormat, binary); +} + +static void glGetQueryObjectuiv(glFunctions *f, GLuint id, GLenum pname, GLuint *params) { + f->glGetQueryObjectuiv(id, pname, params); +} + +static void glMemoryBarrier(glFunctions *f, GLbitfield barriers) { + f->glMemoryBarrier(barriers); +} + +static void glDispatchCompute(glFunctions *f, GLuint x, GLuint y, GLuint z) { + f->glDispatchCompute(x, y, z); +} + +static void *glMapBufferRange(glFunctions *f, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { + return f->glMapBufferRange(target, offset, length, access); +} + +static GLboolean glUnmapBuffer(glFunctions *f, GLenum target) { + return f->glUnmapBuffer(target); +} + +static void glBindImageTexture(glFunctions *f, GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) { + f->glBindImageTexture(unit, texture, level, layered, layer, access, format); +} + +static void glTexStorage2D(glFunctions *f, GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height) { + f->glTexStorage2D(target, levels, internalFormat, width, height); +} + +static void glBlitFramebuffer(glFunctions *f, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { + f->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); +} +*/ +import "C" + +type Context interface{} + +type Functions struct { + // Query caches. + uints [100]C.GLuint + ints [100]C.GLint + floats [100]C.GLfloat + + f C.glFunctions +} + +func NewFunctions(ctx Context, forceES bool) (*Functions, error) { + if ctx != nil { + panic("non-nil context") + } + f := new(Functions) + err := f.load(forceES) + if err != nil { + return nil, err + } + return f, nil +} + +func dlsym(handle unsafe.Pointer, s string) unsafe.Pointer { + cs := C.CString(s) + defer C.free(unsafe.Pointer(cs)) + return C.dlsym(handle, cs) +} + +func dlopen(lib string) unsafe.Pointer { + clib := C.CString(lib) + defer C.free(unsafe.Pointer(clib)) + return C.dlopen(clib, C.RTLD_NOW|C.RTLD_LOCAL) +} + +func (f *Functions) load(forceES bool) error { + var ( + loadErr error + libNames []string + handles []unsafe.Pointer + ) + switch { + case runtime.GOOS == "darwin" && !forceES: + libNames = []string{"/System/Library/Frameworks/OpenGL.framework/OpenGL"} + case runtime.GOOS == "darwin" && forceES: + libNames = []string{"libGLESv2.dylib"} + case runtime.GOOS == "ios": + libNames = []string{"/System/Library/Frameworks/OpenGLES.framework/OpenGLES"} + case runtime.GOOS == "android": + libNames = []string{"libGLESv2.so", "libGLESv3.so"} + default: + libNames = []string{"libGLESv2.so.2"} + } + for _, lib := range libNames { + if h := dlopen(lib); h != nil { + handles = append(handles, h) + } + } + if len(handles) == 0 { + return fmt.Errorf("gl: no OpenGL implementation could be loaded (tried %q)", libNames) + } + load := func(s string) *[0]byte { + for _, h := range handles { + if f := dlsym(h, s); f != nil { + return (*[0]byte)(f) + } + } + return nil + } + must := func(s string) *[0]byte { + ptr := load(s) + if ptr == nil { + loadErr = fmt.Errorf("gl: failed to load symbol %q", s) + } + return ptr + } + // GL ES 2.0 functions. + f.f.glActiveTexture = must("glActiveTexture") + f.f.glAttachShader = must("glAttachShader") + f.f.glBindAttribLocation = must("glBindAttribLocation") + f.f.glBindBuffer = must("glBindBuffer") + f.f.glBindFramebuffer = must("glBindFramebuffer") + f.f.glBindRenderbuffer = must("glBindRenderbuffer") + f.f.glBindTexture = must("glBindTexture") + f.f.glBlendEquation = must("glBlendEquation") + f.f.glBlendFuncSeparate = must("glBlendFuncSeparate") + f.f.glBufferData = must("glBufferData") + f.f.glBufferSubData = must("glBufferSubData") + f.f.glCheckFramebufferStatus = must("glCheckFramebufferStatus") + f.f.glClear = must("glClear") + f.f.glClearColor = must("glClearColor") + f.f.glClearDepthf = must("glClearDepthf") + f.f.glCompileShader = must("glCompileShader") + f.f.glCopyTexSubImage2D = must("glCopyTexSubImage2D") + f.f.glCreateProgram = must("glCreateProgram") + f.f.glCreateShader = must("glCreateShader") + f.f.glDeleteBuffers = must("glDeleteBuffers") + f.f.glDeleteFramebuffers = must("glDeleteFramebuffers") + f.f.glDeleteProgram = must("glDeleteProgram") + f.f.glDeleteRenderbuffers = must("glDeleteRenderbuffers") + f.f.glDeleteShader = must("glDeleteShader") + f.f.glDeleteTextures = must("glDeleteTextures") + f.f.glDepthFunc = must("glDepthFunc") + f.f.glDepthMask = must("glDepthMask") + f.f.glDisable = must("glDisable") + f.f.glDisableVertexAttribArray = must("glDisableVertexAttribArray") + f.f.glDrawArrays = must("glDrawArrays") + f.f.glDrawElements = must("glDrawElements") + f.f.glEnable = must("glEnable") + f.f.glEnableVertexAttribArray = must("glEnableVertexAttribArray") + f.f.glFinish = must("glFinish") + f.f.glFlush = must("glFlush") + f.f.glFramebufferRenderbuffer = must("glFramebufferRenderbuffer") + f.f.glFramebufferTexture2D = must("glFramebufferTexture2D") + f.f.glGenBuffers = must("glGenBuffers") + f.f.glGenFramebuffers = must("glGenFramebuffers") + f.f.glGenRenderbuffers = must("glGenRenderbuffers") + f.f.glGenTextures = must("glGenTextures") + f.f.glGetError = must("glGetError") + f.f.glGetFramebufferAttachmentParameteriv = must("glGetFramebufferAttachmentParameteriv") + f.f.glGetIntegerv = must("glGetIntegerv") + f.f.glGetFloatv = must("glGetFloatv") + f.f.glGetProgramiv = must("glGetProgramiv") + f.f.glGetProgramInfoLog = must("glGetProgramInfoLog") + f.f.glGetRenderbufferParameteriv = must("glGetRenderbufferParameteriv") + f.f.glGetShaderiv = must("glGetShaderiv") + f.f.glGetShaderInfoLog = must("glGetShaderInfoLog") + f.f.glGetString = must("glGetString") + f.f.glGetUniformLocation = must("glGetUniformLocation") + f.f.glGetVertexAttribiv = must("glGetVertexAttribiv") + f.f.glGetVertexAttribPointerv = must("glGetVertexAttribPointerv") + f.f.glIsEnabled = must("glIsEnabled") + f.f.glLinkProgram = must("glLinkProgram") + f.f.glPixelStorei = must("glPixelStorei") + f.f.glReadPixels = must("glReadPixels") + f.f.glRenderbufferStorage = must("glRenderbufferStorage") + f.f.glScissor = must("glScissor") + f.f.glShaderSource = must("glShaderSource") + f.f.glTexImage2D = must("glTexImage2D") + f.f.glTexParameteri = must("glTexParameteri") + f.f.glTexSubImage2D = must("glTexSubImage2D") + f.f.glUniform1f = must("glUniform1f") + f.f.glUniform1i = must("glUniform1i") + f.f.glUniform2f = must("glUniform2f") + f.f.glUniform3f = must("glUniform3f") + f.f.glUniform4f = must("glUniform4f") + f.f.glUseProgram = must("glUseProgram") + f.f.glVertexAttribPointer = must("glVertexAttribPointer") + f.f.glViewport = must("glViewport") + + // Extensions and GL ES 3 functions. + f.f.glBindBufferBase = load("glBindBufferBase") + f.f.glBindVertexArray = load("glBindVertexArray") + f.f.glGetIntegeri_v = load("glGetIntegeri_v") + f.f.glGetUniformBlockIndex = load("glGetUniformBlockIndex") + f.f.glUniformBlockBinding = load("glUniformBlockBinding") + f.f.glInvalidateFramebuffer = load("glInvalidateFramebuffer") + f.f.glGetStringi = load("glGetStringi") + // Fall back to EXT_invalidate_framebuffer if available. + if f.f.glInvalidateFramebuffer == nil { + f.f.glInvalidateFramebuffer = load("glDiscardFramebufferEXT") + } + + f.f.glBeginQuery = load("glBeginQuery") + if f.f.glBeginQuery == nil { + f.f.glBeginQuery = load("glBeginQueryEXT") + } + f.f.glDeleteQueries = load("glDeleteQueries") + if f.f.glDeleteQueries == nil { + f.f.glDeleteQueries = load("glDeleteQueriesEXT") + } + f.f.glEndQuery = load("glEndQuery") + if f.f.glEndQuery == nil { + f.f.glEndQuery = load("glEndQueryEXT") + } + f.f.glGenQueries = load("glGenQueries") + if f.f.glGenQueries == nil { + f.f.glGenQueries = load("glGenQueriesEXT") + } + f.f.glGetQueryObjectuiv = load("glGetQueryObjectuiv") + if f.f.glGetQueryObjectuiv == nil { + f.f.glGetQueryObjectuiv = load("glGetQueryObjectuivEXT") + } + + f.f.glDeleteVertexArrays = load("glDeleteVertexArrays") + f.f.glGenVertexArrays = load("glGenVertexArrays") + f.f.glMemoryBarrier = load("glMemoryBarrier") + f.f.glDispatchCompute = load("glDispatchCompute") + f.f.glMapBufferRange = load("glMapBufferRange") + f.f.glUnmapBuffer = load("glUnmapBuffer") + f.f.glBindImageTexture = load("glBindImageTexture") + f.f.glTexStorage2D = load("glTexStorage2D") + f.f.glBlitFramebuffer = load("glBlitFramebuffer") + f.f.glGetProgramBinary = load("glGetProgramBinary") + + return loadErr +} + +func (f *Functions) ActiveTexture(texture Enum) { + C.glActiveTexture(&f.f, C.GLenum(texture)) +} + +func (f *Functions) AttachShader(p Program, s Shader) { + C.glAttachShader(&f.f, C.GLuint(p.V), C.GLuint(s.V)) +} + +func (f *Functions) BeginQuery(target Enum, query Query) { + C.glBeginQuery(&f.f, C.GLenum(target), C.GLenum(query.V)) +} + +func (f *Functions) BindAttribLocation(p Program, a Attrib, name string) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + C.glBindAttribLocation(&f.f, C.GLuint(p.V), C.GLuint(a), cname) +} + +func (f *Functions) BindBufferBase(target Enum, index int, b Buffer) { + C.glBindBufferBase(&f.f, C.GLenum(target), C.GLuint(index), C.GLuint(b.V)) +} + +func (f *Functions) BindBuffer(target Enum, b Buffer) { + C.glBindBuffer(&f.f, C.GLenum(target), C.GLuint(b.V)) +} + +func (f *Functions) BindFramebuffer(target Enum, fb Framebuffer) { + C.glBindFramebuffer(&f.f, C.GLenum(target), C.GLuint(fb.V)) +} + +func (f *Functions) BindRenderbuffer(target Enum, fb Renderbuffer) { + C.glBindRenderbuffer(&f.f, C.GLenum(target), C.GLuint(fb.V)) +} + +func (f *Functions) BindImageTexture(unit int, t Texture, level int, layered bool, layer int, access, format Enum) { + l := C.GLboolean(FALSE) + if layered { + l = TRUE + } + C.glBindImageTexture(&f.f, C.GLuint(unit), C.GLuint(t.V), C.GLint(level), l, C.GLint(layer), C.GLenum(access), C.GLenum(format)) +} + +func (f *Functions) BindTexture(target Enum, t Texture) { + C.glBindTexture(&f.f, C.GLenum(target), C.GLuint(t.V)) +} + +func (f *Functions) BindVertexArray(a VertexArray) { + C.glBindVertexArray(&f.f, C.GLuint(a.V)) +} + +func (f *Functions) BlendEquation(mode Enum) { + C.glBlendEquation(&f.f, C.GLenum(mode)) +} + +func (f *Functions) BlendFuncSeparate(srcRGB, dstRGB, srcA, dstA Enum) { + C.glBlendFuncSeparate(&f.f, C.GLenum(srcRGB), C.GLenum(dstRGB), C.GLenum(srcA), C.GLenum(dstA)) +} + +func (f *Functions) BlitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1 int, mask Enum, filter Enum) { + C.glBlitFramebuffer(&f.f, + C.GLint(sx0), C.GLint(sy0), C.GLint(sx1), C.GLint(sy1), + C.GLint(dx0), C.GLint(dy0), C.GLint(dx1), C.GLint(dy1), + C.GLenum(mask), C.GLenum(filter), + ) +} + +func (f *Functions) BufferData(target Enum, size int, usage Enum, data []byte) { + var p unsafe.Pointer + if len(data) > 0 { + p = unsafe.Pointer(&data[0]) + } + C.glBufferData(&f.f, C.GLenum(target), C.GLsizeiptr(size), p, C.GLenum(usage)) +} + +func (f *Functions) BufferSubData(target Enum, offset int, src []byte) { + var p unsafe.Pointer + if len(src) > 0 { + p = unsafe.Pointer(&src[0]) + } + C.glBufferSubData(&f.f, C.GLenum(target), C.GLintptr(offset), C.GLsizeiptr(len(src)), p) +} + +func (f *Functions) CheckFramebufferStatus(target Enum) Enum { + return Enum(C.glCheckFramebufferStatus(&f.f, C.GLenum(target))) +} + +func (f *Functions) Clear(mask Enum) { + C.glClear(&f.f, C.GLbitfield(mask)) +} + +func (f *Functions) ClearColor(red float32, green float32, blue float32, alpha float32) { + C.glClearColor(&f.f, C.GLfloat(red), C.GLfloat(green), C.GLfloat(blue), C.GLfloat(alpha)) +} + +func (f *Functions) ClearDepthf(d float32) { + C.glClearDepthf(&f.f, C.GLfloat(d)) +} + +func (f *Functions) CompileShader(s Shader) { + C.glCompileShader(&f.f, C.GLuint(s.V)) +} + +func (f *Functions) CopyTexSubImage2D(target Enum, level, xoffset, yoffset, x, y, width, height int) { + C.glCopyTexSubImage2D(&f.f, C.GLenum(target), C.GLint(level), C.GLint(xoffset), C.GLint(yoffset), C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height)) +} + +func (f *Functions) CreateBuffer() Buffer { + C.glGenBuffers(&f.f, 1, &f.uints[0]) + return Buffer{uint(f.uints[0])} +} + +func (f *Functions) CreateFramebuffer() Framebuffer { + C.glGenFramebuffers(&f.f, 1, &f.uints[0]) + return Framebuffer{uint(f.uints[0])} +} + +func (f *Functions) CreateProgram() Program { + return Program{uint(C.glCreateProgram(&f.f))} +} + +func (f *Functions) CreateQuery() Query { + C.glGenQueries(&f.f, 1, &f.uints[0]) + return Query{uint(f.uints[0])} +} + +func (f *Functions) CreateRenderbuffer() Renderbuffer { + C.glGenRenderbuffers(&f.f, 1, &f.uints[0]) + return Renderbuffer{uint(f.uints[0])} +} + +func (f *Functions) CreateShader(ty Enum) Shader { + return Shader{uint(C.glCreateShader(&f.f, C.GLenum(ty)))} +} + +func (f *Functions) CreateTexture() Texture { + C.glGenTextures(&f.f, 1, &f.uints[0]) + return Texture{uint(f.uints[0])} +} + +func (f *Functions) CreateVertexArray() VertexArray { + C.glGenVertexArrays(&f.f, 1, &f.uints[0]) + return VertexArray{uint(f.uints[0])} +} + +func (f *Functions) DeleteBuffer(v Buffer) { + f.uints[0] = C.GLuint(v.V) + C.glDeleteBuffers(&f.f, 1, &f.uints[0]) +} + +func (f *Functions) DeleteFramebuffer(v Framebuffer) { + f.uints[0] = C.GLuint(v.V) + C.glDeleteFramebuffers(&f.f, 1, &f.uints[0]) +} + +func (f *Functions) DeleteProgram(p Program) { + C.glDeleteProgram(&f.f, C.GLuint(p.V)) +} + +func (f *Functions) DeleteQuery(query Query) { + f.uints[0] = C.GLuint(query.V) + C.glDeleteQueries(&f.f, 1, &f.uints[0]) +} + +func (f *Functions) DeleteVertexArray(array VertexArray) { + f.uints[0] = C.GLuint(array.V) + C.glDeleteVertexArrays(&f.f, 1, &f.uints[0]) +} + +func (f *Functions) DeleteRenderbuffer(v Renderbuffer) { + f.uints[0] = C.GLuint(v.V) + C.glDeleteRenderbuffers(&f.f, 1, &f.uints[0]) +} + +func (f *Functions) DeleteShader(s Shader) { + C.glDeleteShader(&f.f, C.GLuint(s.V)) +} + +func (f *Functions) DeleteTexture(v Texture) { + f.uints[0] = C.GLuint(v.V) + C.glDeleteTextures(&f.f, 1, &f.uints[0]) +} + +func (f *Functions) DepthFunc(v Enum) { + C.glDepthFunc(&f.f, C.GLenum(v)) +} + +func (f *Functions) DepthMask(mask bool) { + m := C.GLboolean(FALSE) + if mask { + m = C.GLboolean(TRUE) + } + C.glDepthMask(&f.f, m) +} + +func (f *Functions) DisableVertexAttribArray(a Attrib) { + C.glDisableVertexAttribArray(&f.f, C.GLuint(a)) +} + +func (f *Functions) Disable(cap Enum) { + C.glDisable(&f.f, C.GLenum(cap)) +} + +func (f *Functions) DrawArrays(mode Enum, first int, count int) { + C.glDrawArrays(&f.f, C.GLenum(mode), C.GLint(first), C.GLsizei(count)) +} + +func (f *Functions) DrawElements(mode Enum, count int, ty Enum, offset int) { + C.glDrawElements(&f.f, C.GLenum(mode), C.GLsizei(count), C.GLenum(ty), C.uintptr_t(offset)) +} + +func (f *Functions) DispatchCompute(x, y, z int) { + C.glDispatchCompute(&f.f, C.GLuint(x), C.GLuint(y), C.GLuint(z)) +} + +func (f *Functions) Enable(cap Enum) { + C.glEnable(&f.f, C.GLenum(cap)) +} + +func (f *Functions) EndQuery(target Enum) { + C.glEndQuery(&f.f, C.GLenum(target)) +} + +func (f *Functions) EnableVertexAttribArray(a Attrib) { + C.glEnableVertexAttribArray(&f.f, C.GLuint(a)) +} + +func (f *Functions) Finish() { + C.glFinish(&f.f) +} + +func (f *Functions) Flush() { + C.glFlush(&f.f) +} + +func (f *Functions) FramebufferRenderbuffer(target, attachment, renderbuffertarget Enum, renderbuffer Renderbuffer) { + C.glFramebufferRenderbuffer(&f.f, C.GLenum(target), C.GLenum(attachment), C.GLenum(renderbuffertarget), C.GLuint(renderbuffer.V)) +} + +func (f *Functions) FramebufferTexture2D(target, attachment, texTarget Enum, t Texture, level int) { + C.glFramebufferTexture2D(&f.f, C.GLenum(target), C.GLenum(attachment), C.GLenum(texTarget), C.GLuint(t.V), C.GLint(level)) +} + +func (c *Functions) GetBinding(pname Enum) Object { + return Object{uint(c.GetInteger(pname))} +} + +func (c *Functions) GetBindingi(pname Enum, idx int) Object { + return Object{uint(c.GetIntegeri(pname, idx))} +} + +func (f *Functions) GetError() Enum { + return Enum(C.glGetError(&f.f)) +} + +func (f *Functions) GetRenderbufferParameteri(target, pname Enum) int { + C.glGetRenderbufferParameteriv(&f.f, C.GLenum(target), C.GLenum(pname), &f.ints[0]) + return int(f.ints[0]) +} + +func (f *Functions) GetFramebufferAttachmentParameteri(target, attachment, pname Enum) int { + C.glGetFramebufferAttachmentParameteriv(&f.f, C.GLenum(target), C.GLenum(attachment), C.GLenum(pname), &f.ints[0]) + return int(f.ints[0]) +} + +func (f *Functions) GetFloat4(pname Enum) [4]float32 { + C.glGetFloatv(&f.f, C.GLenum(pname), &f.floats[0]) + var r [4]float32 + for i := range r { + r[i] = float32(f.floats[i]) + } + return r +} + +func (f *Functions) GetFloat(pname Enum) float32 { + C.glGetFloatv(&f.f, C.GLenum(pname), &f.floats[0]) + return float32(f.floats[0]) +} + +func (f *Functions) GetInteger4(pname Enum) [4]int { + C.glGetIntegerv(&f.f, C.GLenum(pname), &f.ints[0]) + var r [4]int + for i := range r { + r[i] = int(f.ints[i]) + } + return r +} + +func (f *Functions) GetInteger(pname Enum) int { + C.glGetIntegerv(&f.f, C.GLenum(pname), &f.ints[0]) + return int(f.ints[0]) +} + +func (f *Functions) GetIntegeri(pname Enum, idx int) int { + C.glGetIntegeri_v(&f.f, C.GLenum(pname), C.GLuint(idx), &f.ints[0]) + return int(f.ints[0]) +} + +func (f *Functions) GetProgrami(p Program, pname Enum) int { + C.glGetProgramiv(&f.f, C.GLuint(p.V), C.GLenum(pname), &f.ints[0]) + return int(f.ints[0]) +} + +func (f *Functions) GetProgramBinary(p Program) []byte { + sz := f.GetProgrami(p, PROGRAM_BINARY_LENGTH) + if sz == 0 { + return nil + } + buf := make([]byte, sz) + var format C.GLenum + C.glGetProgramBinary(&f.f, C.GLuint(p.V), C.GLsizei(sz), nil, &format, unsafe.Pointer(&buf[0])) + return buf +} + +func (f *Functions) GetProgramInfoLog(p Program) string { + n := f.GetProgrami(p, INFO_LOG_LENGTH) + buf := make([]byte, n) + C.glGetProgramInfoLog(&f.f, C.GLuint(p.V), C.GLsizei(len(buf)), nil, (*C.GLchar)(unsafe.Pointer(&buf[0]))) + return string(buf) +} + +func (f *Functions) GetQueryObjectuiv(query Query, pname Enum) uint { + C.glGetQueryObjectuiv(&f.f, C.GLuint(query.V), C.GLenum(pname), &f.uints[0]) + return uint(f.uints[0]) +} + +func (f *Functions) GetShaderi(s Shader, pname Enum) int { + C.glGetShaderiv(&f.f, C.GLuint(s.V), C.GLenum(pname), &f.ints[0]) + return int(f.ints[0]) +} + +func (f *Functions) GetShaderInfoLog(s Shader) string { + n := f.GetShaderi(s, INFO_LOG_LENGTH) + buf := make([]byte, n) + C.glGetShaderInfoLog(&f.f, C.GLuint(s.V), C.GLsizei(len(buf)), nil, (*C.GLchar)(unsafe.Pointer(&buf[0]))) + return string(buf) +} + +func (f *Functions) getStringi(pname Enum, index int) string { + str := C.glGetStringi(&f.f, C.GLenum(pname), C.GLuint(index)) + if str == nil { + return "" + } + return C.GoString((*C.char)(unsafe.Pointer(str))) +} + +func (f *Functions) GetString(pname Enum) string { + switch { + case runtime.GOOS == "darwin" && pname == EXTENSIONS: + // macOS OpenGL 3 core profile doesn't support glGetString(GL_EXTENSIONS). + // Use glGetStringi(GL_EXTENSIONS, <index>). + var exts []string + nexts := f.GetInteger(NUM_EXTENSIONS) + for i := 0; i < nexts; i++ { + ext := f.getStringi(EXTENSIONS, i) + exts = append(exts, ext) + } + return strings.Join(exts, " ") + default: + str := C.glGetString(&f.f, C.GLenum(pname)) + return C.GoString((*C.char)(unsafe.Pointer(str))) + } +} + +func (f *Functions) GetUniformBlockIndex(p Program, name string) uint { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + return uint(C.glGetUniformBlockIndex(&f.f, C.GLuint(p.V), cname)) +} + +func (f *Functions) GetUniformLocation(p Program, name string) Uniform { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + return Uniform{int(C.glGetUniformLocation(&f.f, C.GLuint(p.V), cname))} +} + +func (f *Functions) GetVertexAttrib(index int, pname Enum) int { + C.glGetVertexAttribiv(&f.f, C.GLuint(index), C.GLenum(pname), &f.ints[0]) + return int(f.ints[0]) +} + +func (f *Functions) GetVertexAttribBinding(index int, pname Enum) Object { + return Object{uint(f.GetVertexAttrib(index, pname))} +} + +func (f *Functions) GetVertexAttribPointer(index int, pname Enum) uintptr { + ptr := C.glGetVertexAttribPointerv(&f.f, C.GLuint(index), C.GLenum(pname)) + return uintptr(ptr) +} + +func (f *Functions) InvalidateFramebuffer(target, attachment Enum) { + C.glInvalidateFramebuffer(&f.f, C.GLenum(target), C.GLenum(attachment)) +} + +func (f *Functions) IsEnabled(cap Enum) bool { + return C.glIsEnabled(&f.f, C.GLenum(cap)) == TRUE +} + +func (f *Functions) LinkProgram(p Program) { + C.glLinkProgram(&f.f, C.GLuint(p.V)) +} + +func (f *Functions) PixelStorei(pname Enum, param int) { + C.glPixelStorei(&f.f, C.GLenum(pname), C.GLint(param)) +} + +func (f *Functions) MemoryBarrier(barriers Enum) { + C.glMemoryBarrier(&f.f, C.GLbitfield(barriers)) +} + +func (f *Functions) MapBufferRange(target Enum, offset, length int, access Enum) []byte { + p := C.glMapBufferRange(&f.f, C.GLenum(target), C.GLintptr(offset), C.GLsizeiptr(length), C.GLbitfield(access)) + if p == nil { + return nil + } + return (*[1 << 30]byte)(p)[:length:length] +} + +func (f *Functions) Scissor(x, y, width, height int32) { + C.glScissor(&f.f, C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height)) +} + +func (f *Functions) ReadPixels(x, y, width, height int, format, ty Enum, data []byte) { + var p unsafe.Pointer + if len(data) > 0 { + p = unsafe.Pointer(&data[0]) + } + C.glReadPixels(&f.f, C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height), C.GLenum(format), C.GLenum(ty), p) +} + +func (f *Functions) RenderbufferStorage(target, internalformat Enum, width, height int) { + C.glRenderbufferStorage(&f.f, C.GLenum(target), C.GLenum(internalformat), C.GLsizei(width), C.GLsizei(height)) +} + +func (f *Functions) ShaderSource(s Shader, src string) { + csrc := C.CString(src) + defer C.free(unsafe.Pointer(csrc)) + strlen := C.GLint(len(src)) + C.glShaderSource(&f.f, C.GLuint(s.V), 1, &csrc, &strlen) +} + +func (f *Functions) TexImage2D(target Enum, level int, internalFormat Enum, width int, height int, format Enum, ty Enum) { + C.glTexImage2D(&f.f, C.GLenum(target), C.GLint(level), C.GLint(internalFormat), C.GLsizei(width), C.GLsizei(height), 0, C.GLenum(format), C.GLenum(ty), nil) +} + +func (f *Functions) TexStorage2D(target Enum, levels int, internalFormat Enum, width, height int) { + C.glTexStorage2D(&f.f, C.GLenum(target), C.GLsizei(levels), C.GLenum(internalFormat), C.GLsizei(width), C.GLsizei(height)) +} + +func (f *Functions) TexSubImage2D(target Enum, level int, x int, y int, width int, height int, format Enum, ty Enum, data []byte) { + var p unsafe.Pointer + if len(data) > 0 { + p = unsafe.Pointer(&data[0]) + } + C.glTexSubImage2D(&f.f, C.GLenum(target), C.GLint(level), C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height), C.GLenum(format), C.GLenum(ty), p) +} + +func (f *Functions) TexParameteri(target, pname Enum, param int) { + C.glTexParameteri(&f.f, C.GLenum(target), C.GLenum(pname), C.GLint(param)) +} + +func (f *Functions) UniformBlockBinding(p Program, uniformBlockIndex uint, uniformBlockBinding uint) { + C.glUniformBlockBinding(&f.f, C.GLuint(p.V), C.GLuint(uniformBlockIndex), C.GLuint(uniformBlockBinding)) +} + +func (f *Functions) Uniform1f(dst Uniform, v float32) { + C.glUniform1f(&f.f, C.GLint(dst.V), C.GLfloat(v)) +} + +func (f *Functions) Uniform1i(dst Uniform, v int) { + C.glUniform1i(&f.f, C.GLint(dst.V), C.GLint(v)) +} + +func (f *Functions) Uniform2f(dst Uniform, v0 float32, v1 float32) { + C.glUniform2f(&f.f, C.GLint(dst.V), C.GLfloat(v0), C.GLfloat(v1)) +} + +func (f *Functions) Uniform3f(dst Uniform, v0 float32, v1 float32, v2 float32) { + C.glUniform3f(&f.f, C.GLint(dst.V), C.GLfloat(v0), C.GLfloat(v1), C.GLfloat(v2)) +} + +func (f *Functions) Uniform4f(dst Uniform, v0 float32, v1 float32, v2 float32, v3 float32) { + C.glUniform4f(&f.f, C.GLint(dst.V), C.GLfloat(v0), C.GLfloat(v1), C.GLfloat(v2), C.GLfloat(v3)) +} + +func (f *Functions) UseProgram(p Program) { + C.glUseProgram(&f.f, C.GLuint(p.V)) +} + +func (f *Functions) UnmapBuffer(target Enum) bool { + r := C.glUnmapBuffer(&f.f, C.GLenum(target)) + return r == TRUE +} + +func (f *Functions) VertexAttribPointer(dst Attrib, size int, ty Enum, normalized bool, stride int, offset int) { + var n C.GLboolean = FALSE + if normalized { + n = TRUE + } + C.glVertexAttribPointer(&f.f, C.GLuint(dst), C.GLint(size), C.GLenum(ty), n, C.GLsizei(stride), C.uintptr_t(offset)) +} + +func (f *Functions) Viewport(x int, y int, width int, height int) { + C.glViewport(&f.f, C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height)) +} diff --git a/vendor/gioui.org/internal/gl/gl_windows.go b/vendor/gioui.org/internal/gl/gl_windows.go new file mode 100644 index 0000000..99b1694 --- /dev/null +++ b/vendor/gioui.org/internal/gl/gl_windows.go @@ -0,0 +1,502 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +package gl + +import ( + "math" + "runtime" + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +var ( + LibGLESv2 = windows.NewLazyDLL("libGLESv2.dll") + _glActiveTexture = LibGLESv2.NewProc("glActiveTexture") + _glAttachShader = LibGLESv2.NewProc("glAttachShader") + _glBeginQuery = LibGLESv2.NewProc("glBeginQuery") + _glBindAttribLocation = LibGLESv2.NewProc("glBindAttribLocation") + _glBindBuffer = LibGLESv2.NewProc("glBindBuffer") + _glBindBufferBase = LibGLESv2.NewProc("glBindBufferBase") + _glBindFramebuffer = LibGLESv2.NewProc("glBindFramebuffer") + _glBindRenderbuffer = LibGLESv2.NewProc("glBindRenderbuffer") + _glBindTexture = LibGLESv2.NewProc("glBindTexture") + _glBindVertexArray = LibGLESv2.NewProc("glBindVertexArray") + _glBlendEquation = LibGLESv2.NewProc("glBlendEquation") + _glBlendFuncSeparate = LibGLESv2.NewProc("glBlendFuncSeparate") + _glBufferData = LibGLESv2.NewProc("glBufferData") + _glBufferSubData = LibGLESv2.NewProc("glBufferSubData") + _glCheckFramebufferStatus = LibGLESv2.NewProc("glCheckFramebufferStatus") + _glClear = LibGLESv2.NewProc("glClear") + _glClearColor = LibGLESv2.NewProc("glClearColor") + _glClearDepthf = LibGLESv2.NewProc("glClearDepthf") + _glDeleteQueries = LibGLESv2.NewProc("glDeleteQueries") + _glDeleteVertexArrays = LibGLESv2.NewProc("glDeleteVertexArrays") + _glCompileShader = LibGLESv2.NewProc("glCompileShader") + _glCopyTexSubImage2D = LibGLESv2.NewProc("glCopyTexSubImage2D") + _glGenBuffers = LibGLESv2.NewProc("glGenBuffers") + _glGenFramebuffers = LibGLESv2.NewProc("glGenFramebuffers") + _glGenVertexArrays = LibGLESv2.NewProc("glGenVertexArrays") + _glGetUniformBlockIndex = LibGLESv2.NewProc("glGetUniformBlockIndex") + _glCreateProgram = LibGLESv2.NewProc("glCreateProgram") + _glGenRenderbuffers = LibGLESv2.NewProc("glGenRenderbuffers") + _glCreateShader = LibGLESv2.NewProc("glCreateShader") + _glGenTextures = LibGLESv2.NewProc("glGenTextures") + _glDeleteBuffers = LibGLESv2.NewProc("glDeleteBuffers") + _glDeleteFramebuffers = LibGLESv2.NewProc("glDeleteFramebuffers") + _glDeleteProgram = LibGLESv2.NewProc("glDeleteProgram") + _glDeleteShader = LibGLESv2.NewProc("glDeleteShader") + _glDeleteRenderbuffers = LibGLESv2.NewProc("glDeleteRenderbuffers") + _glDeleteTextures = LibGLESv2.NewProc("glDeleteTextures") + _glDepthFunc = LibGLESv2.NewProc("glDepthFunc") + _glDepthMask = LibGLESv2.NewProc("glDepthMask") + _glDisableVertexAttribArray = LibGLESv2.NewProc("glDisableVertexAttribArray") + _glDisable = LibGLESv2.NewProc("glDisable") + _glDrawArrays = LibGLESv2.NewProc("glDrawArrays") + _glDrawElements = LibGLESv2.NewProc("glDrawElements") + _glEnable = LibGLESv2.NewProc("glEnable") + _glEnableVertexAttribArray = LibGLESv2.NewProc("glEnableVertexAttribArray") + _glEndQuery = LibGLESv2.NewProc("glEndQuery") + _glFinish = LibGLESv2.NewProc("glFinish") + _glFlush = LibGLESv2.NewProc("glFlush") + _glFramebufferRenderbuffer = LibGLESv2.NewProc("glFramebufferRenderbuffer") + _glFramebufferTexture2D = LibGLESv2.NewProc("glFramebufferTexture2D") + _glGenQueries = LibGLESv2.NewProc("glGenQueries") + _glGetError = LibGLESv2.NewProc("glGetError") + _glGetRenderbufferParameteriv = LibGLESv2.NewProc("glGetRenderbufferParameteriv") + _glGetFloatv = LibGLESv2.NewProc("glGetFloatv") + _glGetFramebufferAttachmentParameteriv = LibGLESv2.NewProc("glGetFramebufferAttachmentParameteriv") + _glGetIntegerv = LibGLESv2.NewProc("glGetIntegerv") + _glGetIntegeri_v = LibGLESv2.NewProc("glGetIntegeri_v") + _glGetProgramiv = LibGLESv2.NewProc("glGetProgramiv") + _glGetProgramInfoLog = LibGLESv2.NewProc("glGetProgramInfoLog") + _glGetQueryObjectuiv = LibGLESv2.NewProc("glGetQueryObjectuiv") + _glGetShaderiv = LibGLESv2.NewProc("glGetShaderiv") + _glGetShaderInfoLog = LibGLESv2.NewProc("glGetShaderInfoLog") + _glGetString = LibGLESv2.NewProc("glGetString") + _glGetUniformLocation = LibGLESv2.NewProc("glGetUniformLocation") + _glGetVertexAttribiv = LibGLESv2.NewProc("glGetVertexAttribiv") + _glGetVertexAttribPointerv = LibGLESv2.NewProc("glGetVertexAttribPointerv") + _glInvalidateFramebuffer = LibGLESv2.NewProc("glInvalidateFramebuffer") + _glIsEnabled = LibGLESv2.NewProc("glIsEnabled") + _glLinkProgram = LibGLESv2.NewProc("glLinkProgram") + _glPixelStorei = LibGLESv2.NewProc("glPixelStorei") + _glReadPixels = LibGLESv2.NewProc("glReadPixels") + _glRenderbufferStorage = LibGLESv2.NewProc("glRenderbufferStorage") + _glScissor = LibGLESv2.NewProc("glScissor") + _glShaderSource = LibGLESv2.NewProc("glShaderSource") + _glTexImage2D = LibGLESv2.NewProc("glTexImage2D") + _glTexStorage2D = LibGLESv2.NewProc("glTexStorage2D") + _glTexSubImage2D = LibGLESv2.NewProc("glTexSubImage2D") + _glTexParameteri = LibGLESv2.NewProc("glTexParameteri") + _glUniformBlockBinding = LibGLESv2.NewProc("glUniformBlockBinding") + _glUniform1f = LibGLESv2.NewProc("glUniform1f") + _glUniform1i = LibGLESv2.NewProc("glUniform1i") + _glUniform2f = LibGLESv2.NewProc("glUniform2f") + _glUniform3f = LibGLESv2.NewProc("glUniform3f") + _glUniform4f = LibGLESv2.NewProc("glUniform4f") + _glUseProgram = LibGLESv2.NewProc("glUseProgram") + _glVertexAttribPointer = LibGLESv2.NewProc("glVertexAttribPointer") + _glViewport = LibGLESv2.NewProc("glViewport") +) + +type Functions struct { + // Query caches. + int32s [100]int32 + float32s [100]float32 + uintptrs [100]uintptr +} + +type Context interface{} + +func NewFunctions(ctx Context, forceES bool) (*Functions, error) { + if ctx != nil { + panic("non-nil context") + } + return new(Functions), nil +} + +func (c *Functions) ActiveTexture(t Enum) { + syscall.Syscall(_glActiveTexture.Addr(), 1, uintptr(t), 0, 0) +} +func (c *Functions) AttachShader(p Program, s Shader) { + syscall.Syscall(_glAttachShader.Addr(), 2, uintptr(p.V), uintptr(s.V), 0) +} +func (f *Functions) BeginQuery(target Enum, query Query) { + syscall.Syscall(_glBeginQuery.Addr(), 2, uintptr(target), uintptr(query.V), 0) +} +func (c *Functions) BindAttribLocation(p Program, a Attrib, name string) { + cname := cString(name) + c0 := &cname[0] + syscall.Syscall(_glBindAttribLocation.Addr(), 3, uintptr(p.V), uintptr(a), uintptr(unsafe.Pointer(c0))) + issue34474KeepAlive(c) +} +func (c *Functions) BindBuffer(target Enum, b Buffer) { + syscall.Syscall(_glBindBuffer.Addr(), 2, uintptr(target), uintptr(b.V), 0) +} +func (c *Functions) BindBufferBase(target Enum, index int, b Buffer) { + syscall.Syscall(_glBindBufferBase.Addr(), 3, uintptr(target), uintptr(index), uintptr(b.V)) +} +func (c *Functions) BindFramebuffer(target Enum, fb Framebuffer) { + syscall.Syscall(_glBindFramebuffer.Addr(), 2, uintptr(target), uintptr(fb.V), 0) +} +func (c *Functions) BindRenderbuffer(target Enum, rb Renderbuffer) { + syscall.Syscall(_glBindRenderbuffer.Addr(), 2, uintptr(target), uintptr(rb.V), 0) +} +func (f *Functions) BindImageTexture(unit int, t Texture, level int, layered bool, layer int, access, format Enum) { + panic("not implemented") +} +func (c *Functions) BindTexture(target Enum, t Texture) { + syscall.Syscall(_glBindTexture.Addr(), 2, uintptr(target), uintptr(t.V), 0) +} +func (c *Functions) BindVertexArray(a VertexArray) { + syscall.Syscall(_glBindVertexArray.Addr(), 1, uintptr(a.V), 0, 0) +} +func (c *Functions) BlendEquation(mode Enum) { + syscall.Syscall(_glBlendEquation.Addr(), 1, uintptr(mode), 0, 0) +} +func (c *Functions) BlendFuncSeparate(srcRGB, dstRGB, srcA, dstA Enum) { + syscall.Syscall6(_glBlendFuncSeparate.Addr(), 4, uintptr(srcRGB), uintptr(dstRGB), uintptr(srcA), uintptr(dstA), 0, 0) +} +func (c *Functions) BufferData(target Enum, size int, usage Enum, data []byte) { + var p unsafe.Pointer + if len(data) > 0 { + p = unsafe.Pointer(&data[0]) + } + syscall.Syscall6(_glBufferData.Addr(), 4, uintptr(target), uintptr(size), uintptr(p), uintptr(usage), 0, 0) +} +func (f *Functions) BufferSubData(target Enum, offset int, src []byte) { + if n := len(src); n > 0 { + s0 := &src[0] + syscall.Syscall6(_glBufferSubData.Addr(), 4, uintptr(target), uintptr(offset), uintptr(n), uintptr(unsafe.Pointer(s0)), 0, 0) + issue34474KeepAlive(s0) + } +} +func (c *Functions) CheckFramebufferStatus(target Enum) Enum { + s, _, _ := syscall.Syscall(_glCheckFramebufferStatus.Addr(), 1, uintptr(target), 0, 0) + return Enum(s) +} +func (c *Functions) Clear(mask Enum) { + syscall.Syscall(_glClear.Addr(), 1, uintptr(mask), 0, 0) +} +func (c *Functions) ClearColor(red, green, blue, alpha float32) { + syscall.Syscall6(_glClearColor.Addr(), 4, uintptr(math.Float32bits(red)), uintptr(math.Float32bits(green)), uintptr(math.Float32bits(blue)), uintptr(math.Float32bits(alpha)), 0, 0) +} +func (c *Functions) ClearDepthf(d float32) { + syscall.Syscall(_glClearDepthf.Addr(), 1, uintptr(math.Float32bits(d)), 0, 0) +} +func (c *Functions) CompileShader(s Shader) { + syscall.Syscall(_glCompileShader.Addr(), 1, uintptr(s.V), 0, 0) +} +func (f *Functions) CopyTexSubImage2D(target Enum, level, xoffset, yoffset, x, y, width, height int) { + syscall.Syscall9(_glCopyTexSubImage2D.Addr(), 8, uintptr(target), uintptr(level), uintptr(xoffset), uintptr(yoffset), uintptr(x), uintptr(y), uintptr(width), uintptr(height), 0) +} +func (c *Functions) CreateBuffer() Buffer { + var buf uintptr + syscall.Syscall(_glGenBuffers.Addr(), 2, 1, uintptr(unsafe.Pointer(&buf)), 0) + return Buffer{uint(buf)} +} +func (c *Functions) CreateFramebuffer() Framebuffer { + var fb uintptr + syscall.Syscall(_glGenFramebuffers.Addr(), 2, 1, uintptr(unsafe.Pointer(&fb)), 0) + return Framebuffer{uint(fb)} +} +func (c *Functions) CreateProgram() Program { + p, _, _ := syscall.Syscall(_glCreateProgram.Addr(), 0, 0, 0, 0) + return Program{uint(p)} +} +func (f *Functions) CreateQuery() Query { + var q uintptr + syscall.Syscall(_glGenQueries.Addr(), 2, 1, uintptr(unsafe.Pointer(&q)), 0) + return Query{uint(q)} +} +func (c *Functions) CreateRenderbuffer() Renderbuffer { + var rb uintptr + syscall.Syscall(_glGenRenderbuffers.Addr(), 2, 1, uintptr(unsafe.Pointer(&rb)), 0) + return Renderbuffer{uint(rb)} +} +func (c *Functions) CreateShader(ty Enum) Shader { + s, _, _ := syscall.Syscall(_glCreateShader.Addr(), 1, uintptr(ty), 0, 0) + return Shader{uint(s)} +} +func (c *Functions) CreateTexture() Texture { + var t uintptr + syscall.Syscall(_glGenTextures.Addr(), 2, 1, uintptr(unsafe.Pointer(&t)), 0) + return Texture{uint(t)} +} +func (c *Functions) CreateVertexArray() VertexArray { + var t uintptr + syscall.Syscall(_glGenVertexArrays.Addr(), 2, 1, uintptr(unsafe.Pointer(&t)), 0) + return VertexArray{uint(t)} +} +func (c *Functions) DeleteBuffer(v Buffer) { + syscall.Syscall(_glDeleteBuffers.Addr(), 2, 1, uintptr(unsafe.Pointer(&v)), 0) +} +func (c *Functions) DeleteFramebuffer(v Framebuffer) { + syscall.Syscall(_glDeleteFramebuffers.Addr(), 2, 1, uintptr(unsafe.Pointer(&v.V)), 0) +} +func (c *Functions) DeleteProgram(p Program) { + syscall.Syscall(_glDeleteProgram.Addr(), 1, uintptr(p.V), 0, 0) +} +func (f *Functions) DeleteQuery(query Query) { + syscall.Syscall(_glDeleteQueries.Addr(), 2, 1, uintptr(unsafe.Pointer(&query.V)), 0) +} +func (c *Functions) DeleteShader(s Shader) { + syscall.Syscall(_glDeleteShader.Addr(), 1, uintptr(s.V), 0, 0) +} +func (c *Functions) DeleteRenderbuffer(v Renderbuffer) { + syscall.Syscall(_glDeleteRenderbuffers.Addr(), 2, 1, uintptr(unsafe.Pointer(&v.V)), 0) +} +func (c *Functions) DeleteTexture(v Texture) { + syscall.Syscall(_glDeleteTextures.Addr(), 2, 1, uintptr(unsafe.Pointer(&v.V)), 0) +} +func (f *Functions) DeleteVertexArray(array VertexArray) { + syscall.Syscall(_glDeleteVertexArrays.Addr(), 2, 1, uintptr(unsafe.Pointer(&array.V)), 0) +} +func (c *Functions) DepthFunc(f Enum) { + syscall.Syscall(_glDepthFunc.Addr(), 1, uintptr(f), 0, 0) +} +func (c *Functions) DepthMask(mask bool) { + var m uintptr + if mask { + m = 1 + } + syscall.Syscall(_glDepthMask.Addr(), 1, m, 0, 0) +} +func (c *Functions) DisableVertexAttribArray(a Attrib) { + syscall.Syscall(_glDisableVertexAttribArray.Addr(), 1, uintptr(a), 0, 0) +} +func (c *Functions) Disable(cap Enum) { + syscall.Syscall(_glDisable.Addr(), 1, uintptr(cap), 0, 0) +} +func (c *Functions) DrawArrays(mode Enum, first, count int) { + syscall.Syscall(_glDrawArrays.Addr(), 3, uintptr(mode), uintptr(first), uintptr(count)) +} +func (c *Functions) DrawElements(mode Enum, count int, ty Enum, offset int) { + syscall.Syscall6(_glDrawElements.Addr(), 4, uintptr(mode), uintptr(count), uintptr(ty), uintptr(offset), 0, 0) +} +func (f *Functions) DispatchCompute(x, y, z int) { + panic("not implemented") +} +func (c *Functions) Enable(cap Enum) { + syscall.Syscall(_glEnable.Addr(), 1, uintptr(cap), 0, 0) +} +func (c *Functions) EnableVertexAttribArray(a Attrib) { + syscall.Syscall(_glEnableVertexAttribArray.Addr(), 1, uintptr(a), 0, 0) +} +func (f *Functions) EndQuery(target Enum) { + syscall.Syscall(_glEndQuery.Addr(), 1, uintptr(target), 0, 0) +} +func (c *Functions) Finish() { + syscall.Syscall(_glFinish.Addr(), 0, 0, 0, 0) +} +func (c *Functions) Flush() { + syscall.Syscall(_glFlush.Addr(), 0, 0, 0, 0) +} +func (c *Functions) FramebufferRenderbuffer(target, attachment, renderbuffertarget Enum, renderbuffer Renderbuffer) { + syscall.Syscall6(_glFramebufferRenderbuffer.Addr(), 4, uintptr(target), uintptr(attachment), uintptr(renderbuffertarget), uintptr(renderbuffer.V), 0, 0) +} +func (c *Functions) FramebufferTexture2D(target, attachment, texTarget Enum, t Texture, level int) { + syscall.Syscall6(_glFramebufferTexture2D.Addr(), 5, uintptr(target), uintptr(attachment), uintptr(texTarget), uintptr(t.V), uintptr(level), 0) +} +func (f *Functions) GetUniformBlockIndex(p Program, name string) uint { + cname := cString(name) + c0 := &cname[0] + u, _, _ := syscall.Syscall(_glGetUniformBlockIndex.Addr(), 2, uintptr(p.V), uintptr(unsafe.Pointer(c0)), 0) + issue34474KeepAlive(c0) + return uint(u) +} +func (c *Functions) GetBinding(pname Enum) Object { + return Object{uint(c.GetInteger(pname))} +} +func (c *Functions) GetBindingi(pname Enum, idx int) Object { + return Object{uint(c.GetIntegeri(pname, idx))} +} +func (c *Functions) GetError() Enum { + e, _, _ := syscall.Syscall(_glGetError.Addr(), 0, 0, 0, 0) + return Enum(e) +} +func (c *Functions) GetRenderbufferParameteri(target, pname Enum) int { + syscall.Syscall(_glGetRenderbufferParameteriv.Addr(), 3, uintptr(target), uintptr(pname), uintptr(unsafe.Pointer(&c.int32s[0]))) + return int(c.int32s[0]) +} +func (c *Functions) GetFramebufferAttachmentParameteri(target, attachment, pname Enum) int { + syscall.Syscall6(_glGetFramebufferAttachmentParameteriv.Addr(), 4, uintptr(target), uintptr(attachment), uintptr(pname), uintptr(unsafe.Pointer(&c.int32s[0])), 0, 0) + return int(c.int32s[0]) +} +func (c *Functions) GetInteger4(pname Enum) [4]int { + syscall.Syscall(_glGetIntegerv.Addr(), 2, uintptr(pname), uintptr(unsafe.Pointer(&c.int32s[0])), 0) + var r [4]int + for i := range r { + r[i] = int(c.int32s[i]) + } + return r +} +func (c *Functions) GetInteger(pname Enum) int { + syscall.Syscall(_glGetIntegerv.Addr(), 2, uintptr(pname), uintptr(unsafe.Pointer(&c.int32s[0])), 0) + return int(c.int32s[0]) +} +func (c *Functions) GetIntegeri(pname Enum, idx int) int { + syscall.Syscall(_glGetIntegeri_v.Addr(), 3, uintptr(pname), uintptr(idx), uintptr(unsafe.Pointer(&c.int32s[0]))) + return int(c.int32s[0]) +} +func (c *Functions) GetFloat(pname Enum) float32 { + syscall.Syscall(_glGetFloatv.Addr(), 2, uintptr(pname), uintptr(unsafe.Pointer(&c.float32s[0])), 0) + return c.float32s[0] +} +func (c *Functions) GetFloat4(pname Enum) [4]float32 { + syscall.Syscall(_glGetFloatv.Addr(), 2, uintptr(pname), uintptr(unsafe.Pointer(&c.float32s[0])), 0) + var r [4]float32 + copy(r[:], c.float32s[:]) + return r +} +func (c *Functions) GetProgrami(p Program, pname Enum) int { + syscall.Syscall(_glGetProgramiv.Addr(), 3, uintptr(p.V), uintptr(pname), uintptr(unsafe.Pointer(&c.int32s[0]))) + return int(c.int32s[0]) +} +func (c *Functions) GetProgramInfoLog(p Program) string { + n := c.GetProgrami(p, INFO_LOG_LENGTH) + buf := make([]byte, n) + syscall.Syscall6(_glGetProgramInfoLog.Addr(), 4, uintptr(p.V), uintptr(len(buf)), 0, uintptr(unsafe.Pointer(&buf[0])), 0, 0) + return string(buf) +} +func (c *Functions) GetQueryObjectuiv(query Query, pname Enum) uint { + syscall.Syscall(_glGetQueryObjectuiv.Addr(), 3, uintptr(query.V), uintptr(pname), uintptr(unsafe.Pointer(&c.int32s[0]))) + return uint(c.int32s[0]) +} +func (c *Functions) GetShaderi(s Shader, pname Enum) int { + syscall.Syscall(_glGetShaderiv.Addr(), 3, uintptr(s.V), uintptr(pname), uintptr(unsafe.Pointer(&c.int32s[0]))) + return int(c.int32s[0]) +} +func (c *Functions) GetShaderInfoLog(s Shader) string { + n := c.GetShaderi(s, INFO_LOG_LENGTH) + buf := make([]byte, n) + syscall.Syscall6(_glGetShaderInfoLog.Addr(), 4, uintptr(s.V), uintptr(len(buf)), 0, uintptr(unsafe.Pointer(&buf[0])), 0, 0) + return string(buf) +} +func (c *Functions) GetString(pname Enum) string { + s, _, _ := syscall.Syscall(_glGetString.Addr(), 1, uintptr(pname), 0, 0) + return windows.BytePtrToString((*byte)(unsafe.Pointer(s))) +} +func (c *Functions) GetUniformLocation(p Program, name string) Uniform { + cname := cString(name) + c0 := &cname[0] + u, _, _ := syscall.Syscall(_glGetUniformLocation.Addr(), 2, uintptr(p.V), uintptr(unsafe.Pointer(c0)), 0) + issue34474KeepAlive(c0) + return Uniform{int(u)} +} +func (c *Functions) GetVertexAttrib(index int, pname Enum) int { + syscall.Syscall(_glGetVertexAttribiv.Addr(), 3, uintptr(index), uintptr(pname), uintptr(unsafe.Pointer(&c.int32s[0]))) + return int(c.int32s[0]) +} + +func (c *Functions) GetVertexAttribBinding(index int, pname Enum) Object { + return Object{uint(c.GetVertexAttrib(index, pname))} +} + +func (c *Functions) GetVertexAttribPointer(index int, pname Enum) uintptr { + syscall.Syscall(_glGetVertexAttribPointerv.Addr(), 3, uintptr(index), uintptr(pname), uintptr(unsafe.Pointer(&c.uintptrs[0]))) + return c.uintptrs[0] +} +func (c *Functions) InvalidateFramebuffer(target, attachment Enum) { + addr := _glInvalidateFramebuffer.Addr() + if addr == 0 { + // InvalidateFramebuffer is just a hint. Skip it if not supported. + return + } + syscall.Syscall(addr, 3, uintptr(target), 1, uintptr(unsafe.Pointer(&attachment))) +} +func (f *Functions) IsEnabled(cap Enum) bool { + u, _, _ := syscall.Syscall(_glIsEnabled.Addr(), 1, uintptr(cap), 0, 0) + return u == TRUE +} +func (c *Functions) LinkProgram(p Program) { + syscall.Syscall(_glLinkProgram.Addr(), 1, uintptr(p.V), 0, 0) +} +func (c *Functions) PixelStorei(pname Enum, param int) { + syscall.Syscall(_glPixelStorei.Addr(), 2, uintptr(pname), uintptr(param), 0) +} +func (f *Functions) MemoryBarrier(barriers Enum) { + panic("not implemented") +} +func (f *Functions) MapBufferRange(target Enum, offset, length int, access Enum) []byte { + panic("not implemented") +} +func (f *Functions) ReadPixels(x, y, width, height int, format, ty Enum, data []byte) { + d0 := &data[0] + syscall.Syscall9(_glReadPixels.Addr(), 7, uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(format), uintptr(ty), uintptr(unsafe.Pointer(d0)), 0, 0) + issue34474KeepAlive(d0) +} +func (c *Functions) RenderbufferStorage(target, internalformat Enum, width, height int) { + syscall.Syscall6(_glRenderbufferStorage.Addr(), 4, uintptr(target), uintptr(internalformat), uintptr(width), uintptr(height), 0, 0) +} +func (c *Functions) Scissor(x, y, width, height int32) { + syscall.Syscall6(_glScissor.Addr(), 4, uintptr(x), uintptr(y), uintptr(width), uintptr(height), 0, 0) +} +func (c *Functions) ShaderSource(s Shader, src string) { + var n uintptr = uintptr(len(src)) + psrc := &src + syscall.Syscall6(_glShaderSource.Addr(), 4, uintptr(s.V), 1, uintptr(unsafe.Pointer(psrc)), uintptr(unsafe.Pointer(&n)), 0, 0) + issue34474KeepAlive(psrc) +} +func (f *Functions) TexImage2D(target Enum, level int, internalFormat Enum, width int, height int, format Enum, ty Enum) { + syscall.Syscall9(_glTexImage2D.Addr(), 9, uintptr(target), uintptr(level), uintptr(internalFormat), uintptr(width), uintptr(height), 0, uintptr(format), uintptr(ty), 0) +} +func (f *Functions) TexStorage2D(target Enum, levels int, internalFormat Enum, width, height int) { + syscall.Syscall6(_glTexStorage2D.Addr(), 5, uintptr(target), uintptr(levels), uintptr(internalFormat), uintptr(width), uintptr(height), 0) +} +func (c *Functions) TexSubImage2D(target Enum, level int, x, y, width, height int, format, ty Enum, data []byte) { + d0 := &data[0] + syscall.Syscall9(_glTexSubImage2D.Addr(), 9, uintptr(target), uintptr(level), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(format), uintptr(ty), uintptr(unsafe.Pointer(d0))) + issue34474KeepAlive(d0) +} +func (c *Functions) TexParameteri(target, pname Enum, param int) { + syscall.Syscall(_glTexParameteri.Addr(), 3, uintptr(target), uintptr(pname), uintptr(param)) +} +func (f *Functions) UniformBlockBinding(p Program, uniformBlockIndex uint, uniformBlockBinding uint) { + syscall.Syscall(_glUniformBlockBinding.Addr(), 3, uintptr(p.V), uintptr(uniformBlockIndex), uintptr(uniformBlockBinding)) +} +func (c *Functions) Uniform1f(dst Uniform, v float32) { + syscall.Syscall(_glUniform1f.Addr(), 2, uintptr(dst.V), uintptr(math.Float32bits(v)), 0) +} +func (c *Functions) Uniform1i(dst Uniform, v int) { + syscall.Syscall(_glUniform1i.Addr(), 2, uintptr(dst.V), uintptr(v), 0) +} +func (c *Functions) Uniform2f(dst Uniform, v0, v1 float32) { + syscall.Syscall(_glUniform2f.Addr(), 3, uintptr(dst.V), uintptr(math.Float32bits(v0)), uintptr(math.Float32bits(v1))) +} +func (c *Functions) Uniform3f(dst Uniform, v0, v1, v2 float32) { + syscall.Syscall6(_glUniform3f.Addr(), 4, uintptr(dst.V), uintptr(math.Float32bits(v0)), uintptr(math.Float32bits(v1)), uintptr(math.Float32bits(v2)), 0, 0) +} +func (c *Functions) Uniform4f(dst Uniform, v0, v1, v2, v3 float32) { + syscall.Syscall6(_glUniform4f.Addr(), 5, uintptr(dst.V), uintptr(math.Float32bits(v0)), uintptr(math.Float32bits(v1)), uintptr(math.Float32bits(v2)), uintptr(math.Float32bits(v3)), 0) +} +func (c *Functions) UseProgram(p Program) { + syscall.Syscall(_glUseProgram.Addr(), 1, uintptr(p.V), 0, 0) +} +func (f *Functions) UnmapBuffer(target Enum) bool { + panic("not implemented") +} +func (c *Functions) VertexAttribPointer(dst Attrib, size int, ty Enum, normalized bool, stride, offset int) { + var norm uintptr + if normalized { + norm = 1 + } + syscall.Syscall6(_glVertexAttribPointer.Addr(), 6, uintptr(dst), uintptr(size), uintptr(ty), norm, uintptr(stride), uintptr(offset)) +} +func (c *Functions) Viewport(x, y, width, height int) { + syscall.Syscall6(_glViewport.Addr(), 4, uintptr(x), uintptr(y), uintptr(width), uintptr(height), 0, 0) +} + +func cString(s string) []byte { + b := make([]byte, len(s)+1) + copy(b, s) + return b +} + +// issue34474KeepAlive calls runtime.KeepAlive as a +// workaround for golang.org/issue/34474. +func issue34474KeepAlive(v interface{}) { + runtime.KeepAlive(v) +} diff --git a/vendor/gioui.org/internal/gl/types.go b/vendor/gioui.org/internal/gl/types.go new file mode 100644 index 0000000..dd24963 --- /dev/null +++ b/vendor/gioui.org/internal/gl/types.go @@ -0,0 +1,77 @@ +//go:build !js +// +build !js + +package gl + +type ( + Object struct{ V uint } + Buffer Object + Framebuffer Object + Program Object + Renderbuffer Object + Shader Object + Texture Object + Query Object + Uniform struct{ V int } + VertexArray Object +) + +func (o Object) valid() bool { + return o.V != 0 +} + +func (o Object) equal(o2 Object) bool { + return o == o2 +} + +func (u Framebuffer) Valid() bool { + return Object(u).valid() +} + +func (u Uniform) Valid() bool { + return u.V != -1 +} + +func (p Program) Valid() bool { + return Object(p).valid() +} + +func (s Shader) Valid() bool { + return Object(s).valid() +} + +func (a VertexArray) Valid() bool { + return Object(a).valid() +} + +func (f Framebuffer) Equal(f2 Framebuffer) bool { + return Object(f).equal(Object(f2)) +} + +func (p Program) Equal(p2 Program) bool { + return Object(p).equal(Object(p2)) +} + +func (s Shader) Equal(s2 Shader) bool { + return Object(s).equal(Object(s2)) +} + +func (u Uniform) Equal(u2 Uniform) bool { + return u == u2 +} + +func (a VertexArray) Equal(a2 VertexArray) bool { + return Object(a).equal(Object(a2)) +} + +func (r Renderbuffer) Equal(r2 Renderbuffer) bool { + return Object(r).equal(Object(r2)) +} + +func (t Texture) Equal(t2 Texture) bool { + return Object(t).equal(Object(t2)) +} + +func (b Buffer) Equal(b2 Buffer) bool { + return Object(b).equal(Object(b2)) +} diff --git a/vendor/gioui.org/internal/gl/types_js.go b/vendor/gioui.org/internal/gl/types_js.go new file mode 100644 index 0000000..8d91a6b --- /dev/null +++ b/vendor/gioui.org/internal/gl/types_js.go @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +package gl + +import "syscall/js" + +type ( + Object js.Value + Buffer Object + Framebuffer Object + Program Object + Renderbuffer Object + Shader Object + Texture Object + Query Object + Uniform Object + VertexArray Object +) + +func (o Object) valid() bool { + return js.Value(o).Truthy() +} + +func (o Object) equal(o2 Object) bool { + return js.Value(o).Equal(js.Value(o2)) +} + +func (b Buffer) Valid() bool { + return Object(b).valid() +} + +func (f Framebuffer) Valid() bool { + return Object(f).valid() +} + +func (p Program) Valid() bool { + return Object(p).valid() +} + +func (r Renderbuffer) Valid() bool { + return Object(r).valid() +} + +func (s Shader) Valid() bool { + return Object(s).valid() +} + +func (t Texture) Valid() bool { + return Object(t).valid() +} + +func (u Uniform) Valid() bool { + return Object(u).valid() +} + +func (a VertexArray) Valid() bool { + return Object(a).valid() +} + +func (f Framebuffer) Equal(f2 Framebuffer) bool { + return Object(f).equal(Object(f2)) +} + +func (p Program) Equal(p2 Program) bool { + return Object(p).equal(Object(p2)) +} + +func (s Shader) Equal(s2 Shader) bool { + return Object(s).equal(Object(s2)) +} + +func (u Uniform) Equal(u2 Uniform) bool { + return Object(u).equal(Object(u2)) +} + +func (a VertexArray) Equal(a2 VertexArray) bool { + return Object(a).equal(Object(a2)) +} + +func (r Renderbuffer) Equal(r2 Renderbuffer) bool { + return Object(r).equal(Object(r2)) +} + +func (t Texture) Equal(t2 Texture) bool { + return Object(t).equal(Object(t2)) +} + +func (b Buffer) Equal(b2 Buffer) bool { + return Object(b).equal(Object(b2)) +} diff --git a/vendor/gioui.org/internal/gl/util.go b/vendor/gioui.org/internal/gl/util.go new file mode 100644 index 0000000..c696b69 --- /dev/null +++ b/vendor/gioui.org/internal/gl/util.go @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +package gl + +import ( + "errors" + "fmt" + "strings" +) + +func CreateProgram(ctx *Functions, vsSrc, fsSrc string, attribs []string) (Program, error) { + vs, err := CreateShader(ctx, VERTEX_SHADER, vsSrc) + if err != nil { + return Program{}, err + } + defer ctx.DeleteShader(vs) + fs, err := CreateShader(ctx, FRAGMENT_SHADER, fsSrc) + if err != nil { + return Program{}, err + } + defer ctx.DeleteShader(fs) + prog := ctx.CreateProgram() + if !prog.Valid() { + return Program{}, errors.New("glCreateProgram failed") + } + ctx.AttachShader(prog, vs) + ctx.AttachShader(prog, fs) + for i, a := range attribs { + ctx.BindAttribLocation(prog, Attrib(i), a) + } + ctx.LinkProgram(prog) + if ctx.GetProgrami(prog, LINK_STATUS) == 0 { + log := ctx.GetProgramInfoLog(prog) + ctx.DeleteProgram(prog) + return Program{}, fmt.Errorf("program link failed: %s", strings.TrimSpace(log)) + } + return prog, nil +} + +func CreateComputeProgram(ctx *Functions, src string) (Program, error) { + cs, err := CreateShader(ctx, COMPUTE_SHADER, src) + if err != nil { + return Program{}, err + } + defer ctx.DeleteShader(cs) + prog := ctx.CreateProgram() + if !prog.Valid() { + return Program{}, errors.New("glCreateProgram failed") + } + ctx.AttachShader(prog, cs) + ctx.LinkProgram(prog) + if ctx.GetProgrami(prog, LINK_STATUS) == 0 { + log := ctx.GetProgramInfoLog(prog) + ctx.DeleteProgram(prog) + return Program{}, fmt.Errorf("program link failed: %s", strings.TrimSpace(log)) + } + return prog, nil +} + +func CreateShader(ctx *Functions, typ Enum, src string) (Shader, error) { + sh := ctx.CreateShader(typ) + if !sh.Valid() { + return Shader{}, errors.New("glCreateShader failed") + } + ctx.ShaderSource(sh, src) + ctx.CompileShader(sh) + if ctx.GetShaderi(sh, COMPILE_STATUS) == 0 { + log := ctx.GetShaderInfoLog(sh) + ctx.DeleteShader(sh) + return Shader{}, fmt.Errorf("shader compilation failed: %s", strings.TrimSpace(log)) + } + return sh, nil +} + +func ParseGLVersion(glVer string) (version [2]int, gles bool, err error) { + var ver [2]int + if _, err := fmt.Sscanf(glVer, "OpenGL ES %d.%d", &ver[0], &ver[1]); err == nil { + return ver, true, nil + } else if _, err := fmt.Sscanf(glVer, "WebGL %d.%d", &ver[0], &ver[1]); err == nil { + // WebGL major version v corresponds to OpenGL ES version v + 1 + ver[0]++ + return ver, true, nil + } else if _, err := fmt.Sscanf(glVer, "%d.%d", &ver[0], &ver[1]); err == nil { + return ver, false, nil + } + return ver, false, fmt.Errorf("failed to parse OpenGL ES version (%s)", glVer) +} diff --git a/vendor/gioui.org/internal/opconst/ops.go b/vendor/gioui.org/internal/opconst/ops.go deleted file mode 100644 index 62365b8..0000000 --- a/vendor/gioui.org/internal/opconst/ops.go +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -package opconst - -type OpType byte - -// Start at a high number for easier debugging. -const firstOpIndex = 200 - -const ( - TypeMacro OpType = iota + firstOpIndex - TypeCall - TypeTransform - TypeLayer - TypeInvalidate - TypeImage - TypePaint - TypeColor - TypeArea - TypePointerInput - TypePass - TypeKeyInput - TypeHideInput - TypePush - TypePop - TypeAux - TypeClip - TypeProfile -) - -const ( - TypeMacroLen = 1 + 4 + 4 - TypeCallLen = 1 + 4 + 4 - TypeTransformLen = 1 + 4*6 - TypeLayerLen = 1 - TypeRedrawLen = 1 + 8 - TypeImageLen = 1 + 4*4 - TypePaintLen = 1 + 4*4 - TypeColorLen = 1 + 4 - TypeAreaLen = 1 + 1 + 4*4 - TypePointerInputLen = 1 + 1 + 1 - TypePassLen = 1 + 1 - TypeKeyInputLen = 1 + 1 - TypeHideInputLen = 1 - TypePushLen = 1 - TypePopLen = 1 - TypeAuxLen = 1 - TypeClipLen = 1 + 4*4 - TypeProfileLen = 1 -) - -func (t OpType) Size() int { - return [...]int{ - TypeMacroLen, - TypeCallLen, - TypeTransformLen, - TypeLayerLen, - TypeRedrawLen, - TypeImageLen, - TypePaintLen, - TypeColorLen, - TypeAreaLen, - TypePointerInputLen, - TypePassLen, - TypeKeyInputLen, - TypeHideInputLen, - TypePushLen, - TypePopLen, - TypeAuxLen, - TypeClipLen, - TypeProfileLen, - }[t-firstOpIndex] -} - -func (t OpType) NumRefs() int { - switch t { - case TypeKeyInput, TypePointerInput, TypeProfile, TypeCall: - return 1 - case TypeImage: - return 2 - default: - return 0 - } -} diff --git a/vendor/gioui.org/internal/ops/ops.go b/vendor/gioui.org/internal/ops/ops.go index c56b9d6..fece6d6 100644 --- a/vendor/gioui.org/internal/ops/ops.go +++ b/vendor/gioui.org/internal/ops/ops.go @@ -4,57 +4,321 @@ package ops import ( "encoding/binary" + "image" "math" "gioui.org/f32" - "gioui.org/internal/opconst" + "gioui.org/internal/byteslice" + "gioui.org/internal/scene" ) -const QuadSize = 4 * 2 * 3 +type Ops struct { + // version is incremented at each Reset. + version int + // data contains the serialized operations. + data []byte + // refs hold external references for operations. + refs []interface{} + // nextStateID is the id allocated for the next + // StateOp. + nextStateID int -type Quad struct { - From, Ctrl, To f32.Point + macroStack stack + stacks [5]stack } -func (q Quad) Transform(t f32.Affine2D) Quad { - q.From = t.Transform(q.From) - q.Ctrl = t.Transform(q.Ctrl) - q.To = t.Transform(q.To) - return q +type OpType byte + +type Shape byte + +// Start at a high number for easier debugging. +const firstOpIndex = 200 + +const ( + TypeMacro OpType = iota + firstOpIndex + TypeCall + TypeDefer + TypePushTransform + TypeTransform + TypePopTransform + TypeInvalidate + TypeImage + TypePaint + TypeColor + TypeLinearGradient + TypePass + TypePopPass + TypePointerInput + TypeClipboardRead + TypeClipboardWrite + TypeSource + TypeTarget + TypeOffer + TypeKeyInput + TypeKeyFocus + TypeKeySoftKeyboard + TypeSave + TypeLoad + TypeAux + TypeClip + TypePopClip + TypeProfile + TypeCursor + TypePath + TypeStroke + TypeSemanticLabel + TypeSemanticDesc + TypeSemanticClass + TypeSemanticSelected + TypeSemanticDisabled +) + +type StackID struct { + id int + prev int +} + +// StateOp represents a saved operation snapshop to be restored +// later. +type StateOp struct { + id int + macroID int + ops *Ops +} + +// stack tracks the integer identities of stack operations to ensure correct +// pairing of their push and pop methods. +type stack struct { + currentID int + nextID int +} + +type StackKind uint8 + +// ClipOp is the shadow of clip.Op. +type ClipOp struct { + Bounds image.Rectangle + Outline bool + Shape Shape } -func EncodeQuad(d []byte, q Quad) { +const ( + ClipStack StackKind = iota + TransStack + PassStack + MetaStack +) + +const ( + Path Shape = iota + Ellipse + Rect +) + +const ( + TypeMacroLen = 1 + 4 + 4 + TypeCallLen = 1 + 4 + 4 + TypeDeferLen = 1 + TypePushTransformLen = 1 + 4*6 + TypeTransformLen = 1 + 1 + 4*6 + TypePopTransformLen = 1 + TypeRedrawLen = 1 + 8 + TypeImageLen = 1 + TypePaintLen = 1 + TypeColorLen = 1 + 4 + TypeLinearGradientLen = 1 + 8*2 + 4*2 + TypePassLen = 1 + TypePopPassLen = 1 + TypePointerInputLen = 1 + 1 + 1*2 + 2*4 + 2*4 + TypeClipboardReadLen = 1 + TypeClipboardWriteLen = 1 + TypeSourceLen = 1 + TypeTargetLen = 1 + TypeOfferLen = 1 + TypeKeyInputLen = 1 + 1 + TypeKeyFocusLen = 1 + 1 + TypeKeySoftKeyboardLen = 1 + 1 + TypeSaveLen = 1 + 4 + TypeLoadLen = 1 + 4 + TypeAuxLen = 1 + TypeClipLen = 1 + 4*4 + 1 + 1 + TypePopClipLen = 1 + TypeProfileLen = 1 + TypeCursorLen = 1 + 1 + TypePathLen = 8 + 1 + TypeStrokeLen = 1 + 4 + TypeSemanticLabelLen = 1 + TypeSemanticDescLen = 1 + TypeSemanticClassLen = 2 + TypeSemanticSelectedLen = 2 + TypeSemanticDisabledLen = 2 +) + +func (op *ClipOp) Decode(data []byte) { + if OpType(data[0]) != TypeClip { + panic("invalid op") + } bo := binary.LittleEndian - bo.PutUint32(d[0:], math.Float32bits(q.From.X)) - bo.PutUint32(d[4:], math.Float32bits(q.From.Y)) - bo.PutUint32(d[8:], math.Float32bits(q.Ctrl.X)) - bo.PutUint32(d[12:], math.Float32bits(q.Ctrl.Y)) - bo.PutUint32(d[16:], math.Float32bits(q.To.X)) - bo.PutUint32(d[20:], math.Float32bits(q.To.Y)) + r := image.Rectangle{ + Min: image.Point{ + X: int(int32(bo.Uint32(data[1:]))), + Y: int(int32(bo.Uint32(data[5:]))), + }, + Max: image.Point{ + X: int(int32(bo.Uint32(data[9:]))), + Y: int(int32(bo.Uint32(data[13:]))), + }, + } + *op = ClipOp{ + Bounds: r, + Outline: data[17] == 1, + Shape: Shape(data[18]), + } } -func DecodeQuad(d []byte) (q Quad) { +func Reset(o *Ops) { + o.macroStack = stack{} + for i := range o.stacks { + o.stacks[i] = stack{} + } + // Leave references to the GC. + for i := range o.refs { + o.refs[i] = nil + } + o.data = o.data[:0] + o.refs = o.refs[:0] + o.nextStateID = 0 + o.version++ +} + +func Write(o *Ops, n int) []byte { + o.data = append(o.data, make([]byte, n)...) + return o.data[len(o.data)-n:] +} + +func PushMacro(o *Ops) StackID { + return o.macroStack.push() +} + +func PopMacro(o *Ops, id StackID) { + o.macroStack.pop(id) +} + +func FillMacro(o *Ops, startPC PC) { + pc := PCFor(o) + // Fill out the macro definition reserved in Record. + data := o.data[startPC.data:] + data = data[:TypeMacroLen] + data[0] = byte(TypeMacro) bo := binary.LittleEndian - q.From.X = math.Float32frombits(bo.Uint32(d[0:])) - q.From.Y = math.Float32frombits(bo.Uint32(d[4:])) - q.Ctrl.X = math.Float32frombits(bo.Uint32(d[8:])) - q.Ctrl.Y = math.Float32frombits(bo.Uint32(d[12:])) - q.To.X = math.Float32frombits(bo.Uint32(d[16:])) - q.To.Y = math.Float32frombits(bo.Uint32(d[20:])) - return + bo.PutUint32(data[1:], uint32(pc.data)) + bo.PutUint32(data[5:], uint32(pc.refs)) } -func DecodeTransform(d []byte) (t f32.Affine2D) { - if opconst.OpType(d[0]) != opconst.TypeTransform { - panic("invalid op") +func AddCall(o *Ops, callOps *Ops, pc PC) { + data := Write1(o, TypeCallLen, callOps) + data[0] = byte(TypeCall) + bo := binary.LittleEndian + bo.PutUint32(data[1:], uint32(pc.data)) + bo.PutUint32(data[5:], uint32(pc.refs)) +} + +func PushOp(o *Ops, kind StackKind) (StackID, int) { + return o.stacks[kind].push(), o.macroStack.currentID +} + +func PopOp(o *Ops, kind StackKind, sid StackID, macroID int) { + if o.macroStack.currentID != macroID { + panic("stack push and pop must not cross macro boundary") } - if len(d) < 1+6*4 { - panic("too short buffer") + o.stacks[kind].pop(sid) +} + +func Write1(o *Ops, n int, ref1 interface{}) []byte { + o.data = append(o.data, make([]byte, n)...) + o.refs = append(o.refs, ref1) + return o.data[len(o.data)-n:] +} + +func Write2(o *Ops, n int, ref1, ref2 interface{}) []byte { + o.data = append(o.data, make([]byte, n)...) + o.refs = append(o.refs, ref1, ref2) + return o.data[len(o.data)-n:] +} + +func Write3(o *Ops, n int, ref1, ref2, ref3 interface{}) []byte { + o.data = append(o.data, make([]byte, n)...) + o.refs = append(o.refs, ref1, ref2, ref3) + return o.data[len(o.data)-n:] +} + +func PCFor(o *Ops) PC { + return PC{data: len(o.data), refs: len(o.refs)} +} + +func (s *stack) push() StackID { + s.nextID++ + sid := StackID{ + id: s.nextID, + prev: s.currentID, } - return decodeAffine2D(d[1:]) + s.currentID = s.nextID + return sid +} + +func (s *stack) check(sid StackID) { + if s.currentID != sid.id { + panic("unbalanced operation") + } +} + +func (s *stack) pop(sid StackID) { + s.check(sid) + s.currentID = sid.prev +} + +// Save the effective transformation. +func Save(o *Ops) StateOp { + o.nextStateID++ + s := StateOp{ + ops: o, + id: o.nextStateID, + macroID: o.macroStack.currentID, + } + bo := binary.LittleEndian + data := Write(o, TypeSaveLen) + data[0] = byte(TypeSave) + bo.PutUint32(data[1:], uint32(s.id)) + return s +} + +// Load a previously saved operations state given +// its ID. +func (s StateOp) Load() { + bo := binary.LittleEndian + data := Write(s.ops, TypeLoadLen) + data[0] = byte(TypeLoad) + bo.PutUint32(data[1:], uint32(s.id)) +} + +func DecodeCommand(d []byte) scene.Command { + var cmd scene.Command + copy(byteslice.Uint32(cmd[:]), d) + return cmd +} + +func EncodeCommand(out []byte, cmd scene.Command) { + copy(out, byteslice.Uint32(cmd[:])) } -func decodeAffine2D(data []byte) f32.Affine2D { +func DecodeTransform(data []byte) (t f32.Affine2D, push bool) { + if OpType(data[0]) != TypeTransform { + panic("invalid op") + } + push = data[1] != 0 + data = data[2:] + data = data[:4*6] + bo := binary.LittleEndian a := math.Float32frombits(bo.Uint32(data)) b := math.Float32frombits(bo.Uint32(data[4*1:])) @@ -62,5 +326,148 @@ func decodeAffine2D(data []byte) f32.Affine2D { d := math.Float32frombits(bo.Uint32(data[4*3:])) e := math.Float32frombits(bo.Uint32(data[4*4:])) f := math.Float32frombits(bo.Uint32(data[4*5:])) - return f32.NewAffine2D(a, b, c, d, e, f) + return f32.NewAffine2D(a, b, c, d, e, f), push +} + +// DecodeSave decodes the state id of a save op. +func DecodeSave(data []byte) int { + if OpType(data[0]) != TypeSave { + panic("invalid op") + } + bo := binary.LittleEndian + return int(bo.Uint32(data[1:])) +} + +// DecodeLoad decodes the state id of a load op. +func DecodeLoad(data []byte) int { + if OpType(data[0]) != TypeLoad { + panic("invalid op") + } + bo := binary.LittleEndian + return int(bo.Uint32(data[1:])) +} + +func (t OpType) Size() int { + return [...]int{ + TypeMacroLen, + TypeCallLen, + TypeDeferLen, + TypePushTransformLen, + TypeTransformLen, + TypePopTransformLen, + TypeRedrawLen, + TypeImageLen, + TypePaintLen, + TypeColorLen, + TypeLinearGradientLen, + TypePassLen, + TypePopPassLen, + TypePointerInputLen, + TypeClipboardReadLen, + TypeClipboardWriteLen, + TypeSourceLen, + TypeTargetLen, + TypeOfferLen, + TypeKeyInputLen, + TypeKeyFocusLen, + TypeKeySoftKeyboardLen, + TypeSaveLen, + TypeLoadLen, + TypeAuxLen, + TypeClipLen, + TypePopClipLen, + TypeProfileLen, + TypeCursorLen, + TypePathLen, + TypeStrokeLen, + TypeSemanticLabelLen, + TypeSemanticDescLen, + TypeSemanticClassLen, + TypeSemanticSelectedLen, + TypeSemanticDisabledLen, + }[t-firstOpIndex] +} + +func (t OpType) NumRefs() int { + switch t { + case TypeKeyInput, TypeKeyFocus, TypePointerInput, TypeProfile, TypeCall, TypeClipboardRead, TypeClipboardWrite, TypeCursor, TypeSemanticLabel, TypeSemanticDesc: + return 1 + case TypeImage, TypeSource, TypeTarget: + return 2 + case TypeOffer: + return 3 + default: + return 0 + } +} + +func (t OpType) String() string { + switch t { + case TypeMacro: + return "Macro" + case TypeCall: + return "Call" + case TypeDefer: + return "Defer" + case TypePushTransform: + return "PushTransform" + case TypeTransform: + return "Transform" + case TypePopTransform: + return "PopTransform" + case TypeInvalidate: + return "Invalidate" + case TypeImage: + return "Image" + case TypePaint: + return "Paint" + case TypeColor: + return "Color" + case TypeLinearGradient: + return "LinearGradient" + case TypePass: + return "Pass" + case TypePopPass: + return "PopPass" + case TypePointerInput: + return "PointerInput" + case TypeClipboardRead: + return "ClipboardRead" + case TypeClipboardWrite: + return "ClipboardWrite" + case TypeSource: + return "Source" + case TypeTarget: + return "Target" + case TypeOffer: + return "Offer" + case TypeKeyInput: + return "KeyInput" + case TypeKeyFocus: + return "KeyFocus" + case TypeKeySoftKeyboard: + return "KeySoftKeyboard" + case TypeSave: + return "Save" + case TypeLoad: + return "Load" + case TypeAux: + return "Aux" + case TypeClip: + return "Clip" + case TypePopClip: + return "PopClip" + case TypeProfile: + return "Profile" + case TypeCursor: + return "Cursor" + case TypePath: + return "Path" + case TypeStroke: + return "Stroke" + case TypeSemanticLabel: + return "SemanticDescription" + default: + panic("unknown OpType") + } } diff --git a/vendor/gioui.org/internal/ops/reader.go b/vendor/gioui.org/internal/ops/reader.go index 5d713db..99b8cb6 100644 --- a/vendor/gioui.org/internal/ops/reader.go +++ b/vendor/gioui.org/internal/ops/reader.go @@ -4,17 +4,15 @@ package ops import ( "encoding/binary" - - "gioui.org/f32" - "gioui.org/internal/opconst" - "gioui.org/op" ) // Reader parses an ops list. type Reader struct { - pc pc - stack []macro - ops *op.Ops + pc PC + stack []macro + ops *Ops + deferOps Ops + deferDone bool } // EncodedOp represents an encoded op returned by @@ -27,53 +25,52 @@ type EncodedOp struct { // Key is a unique key for a given op. type Key struct { - ops *op.Ops - pc int - version int - sx, hx, sy, hy float32 + ops *Ops + pc int + version int } // Shadow of op.MacroOp. type macroOp struct { - ops *op.Ops - pc pc + ops *Ops + pc PC } -type pc struct { +// PC is an instruction counter for an operation list. +type PC struct { data int refs int } type macro struct { - ops *op.Ops - retPC pc - endPC pc + ops *Ops + retPC PC + endPC PC } type opMacroDef struct { - endpc pc + endpc PC } -// Reset start reading from the op list. -func (r *Reader) Reset(ops *op.Ops) { - r.stack = r.stack[:0] - r.pc = pc{} - r.ops = ops +// Reset start reading from the beginning of ops. +func (r *Reader) Reset(ops *Ops) { + r.ResetAt(ops, PC{}) } -func (k Key) SetTransform(t f32.Affine2D) Key { - sx, hx, _, hy, sy, _ := t.Elems() - k.sx = sx - k.hx = hx - k.hy = hy - k.sy = sy - return k +// ResetAt is like Reset, except it starts reading from pc. +func (r *Reader) ResetAt(ops *Ops, pc PC) { + r.stack = r.stack[:0] + Reset(&r.deferOps) + r.deferDone = false + r.pc = pc + r.ops = ops } func (r *Reader) Decode() (EncodedOp, bool) { if r.ops == nil { return EncodedOp{}, false } + deferring := false for { if len(r.stack) > 0 { b := r.stack[len(r.stack)-1] @@ -84,35 +81,59 @@ func (r *Reader) Decode() (EncodedOp, bool) { continue } } - data := r.ops.Data() + data := r.ops.data data = data[r.pc.data:] + refs := r.ops.refs if len(data) == 0 { - return EncodedOp{}, false + if r.deferDone { + return EncodedOp{}, false + } + r.deferDone = true + // Execute deferred macros. + r.ops = &r.deferOps + r.pc = PC{} + continue } - key := Key{ops: r.ops, pc: r.pc.data, version: r.ops.Version()} - t := opconst.OpType(data[0]) + key := Key{ops: r.ops, pc: r.pc.data, version: r.ops.version} + t := OpType(data[0]) n := t.Size() nrefs := t.NumRefs() data = data[:n] - refs := r.ops.Refs() refs = refs[r.pc.refs:] refs = refs[:nrefs] switch t { - case opconst.TypeAux: + case TypeDefer: + deferring = true + r.pc.data += n + r.pc.refs += nrefs + continue + case TypeAux: // An Aux operations is always wrapped in a macro, and // its length is the remaining space. block := r.stack[len(r.stack)-1] - n += block.endPC.data - r.pc.data - opconst.TypeAuxLen + n += block.endPC.data - r.pc.data - TypeAuxLen data = data[:n] - case opconst.TypeCall: + case TypeCall: + if deferring { + deferring = false + // Copy macro for deferred execution. + if t.NumRefs() != 1 { + panic("internal error: unexpected number of macro refs") + } + deferData := Write1(&r.deferOps, t.Size(), refs[0]) + copy(deferData, data) + r.pc.data += n + r.pc.refs += nrefs + continue + } var op macroOp op.decode(data, refs) - macroData := op.ops.Data()[op.pc.data:] - if opconst.OpType(macroData[0]) != opconst.TypeMacro { + macroData := op.ops.data[op.pc.data:] + if OpType(macroData[0]) != TypeMacro { panic("invalid macro reference") } var opDef opMacroDef - opDef.decode(macroData[:opconst.TypeMacro.Size()]) + opDef.decode(macroData[:TypeMacro.Size()]) retPC := r.pc retPC.data += n retPC.refs += nrefs @@ -123,10 +144,10 @@ func (r *Reader) Decode() (EncodedOp, bool) { }) r.ops = op.ops r.pc = op.pc - r.pc.data += opconst.TypeMacro.Size() - r.pc.refs += opconst.TypeMacro.NumRefs() + r.pc.data += TypeMacro.Size() + r.pc.refs += TypeMacro.NumRefs() continue - case opconst.TypeMacro: + case TypeMacro: var op opMacroDef op.decode(data) r.pc = op.endpc @@ -139,14 +160,15 @@ func (r *Reader) Decode() (EncodedOp, bool) { } func (op *opMacroDef) decode(data []byte) { - if opconst.OpType(data[0]) != opconst.TypeMacro { + if OpType(data[0]) != TypeMacro { panic("invalid op") } bo := binary.LittleEndian + data = data[:9] dataIdx := int(int32(bo.Uint32(data[1:]))) refsIdx := int(int32(bo.Uint32(data[5:]))) *op = opMacroDef{ - endpc: pc{ + endpc: PC{ data: dataIdx, refs: refsIdx, }, @@ -154,15 +176,16 @@ func (op *opMacroDef) decode(data []byte) { } func (m *macroOp) decode(data []byte, refs []interface{}) { - if opconst.OpType(data[0]) != opconst.TypeCall { + if OpType(data[0]) != TypeCall { panic("invalid op") } + data = data[:9] bo := binary.LittleEndian dataIdx := int(int32(bo.Uint32(data[1:]))) refsIdx := int(int32(bo.Uint32(data[5:]))) *m = macroOp{ - ops: refs[0].(*op.Ops), - pc: pc{ + ops: refs[0].(*Ops), + pc: PC{ data: dataIdx, refs: refsIdx, }, diff --git a/vendor/gioui.org/internal/scene/scene.go b/vendor/gioui.org/internal/scene/scene.go new file mode 100644 index 0000000..0358858 --- /dev/null +++ b/vendor/gioui.org/internal/scene/scene.go @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +// Package scene encodes and decodes graphics commands in the format used by the +// compute renderer. +package scene + +import ( + "fmt" + "image" + "image/color" + "math" + "unsafe" + + "gioui.org/f32" +) + +type Op uint32 + +type Command [sceneElemSize / 4]uint32 + +// GPU commands from piet/scene.h in package gioui.org/shaders. +const ( + OpNop Op = iota + OpLine + OpQuad + OpCubic + OpFillColor + OpLineWidth + OpTransform + OpBeginClip + OpEndClip + OpFillImage + OpSetFillMode + OpGap +) + +// FillModes, from setup.h. +type FillMode uint32 + +const ( + FillModeNonzero = 0 + FillModeStroke = 1 +) + +const CommandSize = int(unsafe.Sizeof(Command{})) + +const sceneElemSize = 36 + +func (c Command) Op() Op { + return Op(c[0]) +} + +func (c Command) String() string { + switch Op(c[0]) { + case OpNop: + return "nop" + case OpLine: + from, to := DecodeLine(c) + return fmt.Sprintf("line(%v, %v)", from, to) + case OpGap: + from, to := DecodeLine(c) + return fmt.Sprintf("gap(%v, %v)", from, to) + case OpQuad: + from, ctrl, to := DecodeQuad(c) + return fmt.Sprintf("quad(%v, %v, %v)", from, ctrl, to) + case OpCubic: + from, ctrl0, ctrl1, to := DecodeCubic(c) + return fmt.Sprintf("cubic(%v, %v, %v, %v)", from, ctrl0, ctrl1, to) + case OpFillColor: + return fmt.Sprintf("fillcolor %#.8x", c[1]) + case OpLineWidth: + return "linewidth" + case OpTransform: + t := f32.NewAffine2D( + math.Float32frombits(c[1]), + math.Float32frombits(c[3]), + math.Float32frombits(c[5]), + math.Float32frombits(c[2]), + math.Float32frombits(c[4]), + math.Float32frombits(c[6]), + ) + return fmt.Sprintf("transform (%v)", t) + case OpBeginClip: + bounds := f32.Rectangle{ + Min: f32.Pt(math.Float32frombits(c[1]), math.Float32frombits(c[2])), + Max: f32.Pt(math.Float32frombits(c[3]), math.Float32frombits(c[4])), + } + return fmt.Sprintf("beginclip (%v)", bounds) + case OpEndClip: + bounds := f32.Rectangle{ + Min: f32.Pt(math.Float32frombits(c[1]), math.Float32frombits(c[2])), + Max: f32.Pt(math.Float32frombits(c[3]), math.Float32frombits(c[4])), + } + return fmt.Sprintf("endclip (%v)", bounds) + case OpFillImage: + return "fillimage" + case OpSetFillMode: + return "setfillmode" + default: + panic("unreachable") + } +} + +func Line(start, end f32.Point) Command { + return Command{ + 0: uint32(OpLine), + 1: math.Float32bits(start.X), + 2: math.Float32bits(start.Y), + 3: math.Float32bits(end.X), + 4: math.Float32bits(end.Y), + } +} + +func Gap(start, end f32.Point) Command { + return Command{ + 0: uint32(OpGap), + 1: math.Float32bits(start.X), + 2: math.Float32bits(start.Y), + 3: math.Float32bits(end.X), + 4: math.Float32bits(end.Y), + } +} + +func Cubic(start, ctrl0, ctrl1, end f32.Point) Command { + return Command{ + 0: uint32(OpCubic), + 1: math.Float32bits(start.X), + 2: math.Float32bits(start.Y), + 3: math.Float32bits(ctrl0.X), + 4: math.Float32bits(ctrl0.Y), + 5: math.Float32bits(ctrl1.X), + 6: math.Float32bits(ctrl1.Y), + 7: math.Float32bits(end.X), + 8: math.Float32bits(end.Y), + } +} + +func Quad(start, ctrl, end f32.Point) Command { + return Command{ + 0: uint32(OpQuad), + 1: math.Float32bits(start.X), + 2: math.Float32bits(start.Y), + 3: math.Float32bits(ctrl.X), + 4: math.Float32bits(ctrl.Y), + 5: math.Float32bits(end.X), + 6: math.Float32bits(end.Y), + } +} + +func Transform(m f32.Affine2D) Command { + sx, hx, ox, hy, sy, oy := m.Elems() + return Command{ + 0: uint32(OpTransform), + 1: math.Float32bits(sx), + 2: math.Float32bits(hy), + 3: math.Float32bits(hx), + 4: math.Float32bits(sy), + 5: math.Float32bits(ox), + 6: math.Float32bits(oy), + } +} + +func SetLineWidth(width float32) Command { + return Command{ + 0: uint32(OpLineWidth), + 1: math.Float32bits(width), + } +} + +func BeginClip(bbox f32.Rectangle) Command { + return Command{ + 0: uint32(OpBeginClip), + 1: math.Float32bits(bbox.Min.X), + 2: math.Float32bits(bbox.Min.Y), + 3: math.Float32bits(bbox.Max.X), + 4: math.Float32bits(bbox.Max.Y), + } +} + +func EndClip(bbox f32.Rectangle) Command { + return Command{ + 0: uint32(OpEndClip), + 1: math.Float32bits(bbox.Min.X), + 2: math.Float32bits(bbox.Min.Y), + 3: math.Float32bits(bbox.Max.X), + 4: math.Float32bits(bbox.Max.Y), + } +} + +func FillColor(col color.RGBA) Command { + return Command{ + 0: uint32(OpFillColor), + 1: uint32(col.R)<<24 | uint32(col.G)<<16 | uint32(col.B)<<8 | uint32(col.A), + } +} + +func FillImage(index int, offset image.Point) Command { + x := int16(offset.X) + y := int16(offset.Y) + return Command{ + 0: uint32(OpFillImage), + 1: uint32(index), + 2: uint32(uint16(x)) | uint32(uint16(y))<<16, + } +} + +func SetFillMode(mode FillMode) Command { + return Command{ + 0: uint32(OpSetFillMode), + 1: uint32(mode), + } +} + +func DecodeLine(cmd Command) (from, to f32.Point) { + if cmd[0] != uint32(OpLine) { + panic("invalid command") + } + from = f32.Pt(math.Float32frombits(cmd[1]), math.Float32frombits(cmd[2])) + to = f32.Pt(math.Float32frombits(cmd[3]), math.Float32frombits(cmd[4])) + return +} + +func DecodeGap(cmd Command) (from, to f32.Point) { + if cmd[0] != uint32(OpGap) { + panic("invalid command") + } + from = f32.Pt(math.Float32frombits(cmd[1]), math.Float32frombits(cmd[2])) + to = f32.Pt(math.Float32frombits(cmd[3]), math.Float32frombits(cmd[4])) + return +} + +func DecodeQuad(cmd Command) (from, ctrl, to f32.Point) { + if cmd[0] != uint32(OpQuad) { + panic("invalid command") + } + from = f32.Pt(math.Float32frombits(cmd[1]), math.Float32frombits(cmd[2])) + ctrl = f32.Pt(math.Float32frombits(cmd[3]), math.Float32frombits(cmd[4])) + to = f32.Pt(math.Float32frombits(cmd[5]), math.Float32frombits(cmd[6])) + return +} + +func DecodeCubic(cmd Command) (from, ctrl0, ctrl1, to f32.Point) { + if cmd[0] != uint32(OpCubic) { + panic("invalid command") + } + from = f32.Pt(math.Float32frombits(cmd[1]), math.Float32frombits(cmd[2])) + ctrl0 = f32.Pt(math.Float32frombits(cmd[3]), math.Float32frombits(cmd[4])) + ctrl1 = f32.Pt(math.Float32frombits(cmd[5]), math.Float32frombits(cmd[6])) + to = f32.Pt(math.Float32frombits(cmd[7]), math.Float32frombits(cmd[8])) + return +} diff --git a/vendor/gioui.org/internal/stroke/stroke.go b/vendor/gioui.org/internal/stroke/stroke.go new file mode 100644 index 0000000..47db6ca --- /dev/null +++ b/vendor/gioui.org/internal/stroke/stroke.go @@ -0,0 +1,742 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +// Most of the algorithms to compute strokes and their offsets have been +// extracted, adapted from (and used as a reference implementation): +// - github.com/tdewolff/canvas (Licensed under MIT) +// +// These algorithms have been implemented from: +// Fast, precise flattening of cubic Bézier path and offset curves +// Thomas F. Hain, et al. +// +// An electronic version is available at: +// https://seant23.files.wordpress.com/2010/11/fastpreciseflatteningofbeziercurve.pdf +// +// Possible improvements (in term of speed and/or accuracy) on these +// algorithms are: +// +// - Polar Stroking: New Theory and Methods for Stroking Paths, +// M. Kilgard +// https://arxiv.org/pdf/2007.00308.pdf +// +// - https://raphlinus.github.io/graphics/curves/2019/12/23/flatten-quadbez.html +// R. Levien + +// Package stroke implements conversion of strokes to filled outlines. It is used as a +// fallback for stroke configurations not natively supported by the renderer. +package stroke + +import ( + "encoding/binary" + "math" + + "gioui.org/f32" + "gioui.org/internal/ops" + "gioui.org/internal/scene" +) + +// The following are copies of types from op/clip to avoid a circular import of +// that package. +// TODO: when the old renderer is gone, this package can be merged with +// op/clip, eliminating the duplicate types. +type StrokeStyle struct { + Width float32 +} + +// strokeTolerance is used to reconcile rounding errors arising +// when splitting quads into smaller and smaller segments to approximate +// them into straight lines, and when joining back segments. +// +// The magic value of 0.01 was found by striking a compromise between +// aesthetic looking (curves did look like curves, even after linearization) +// and speed. +const strokeTolerance = 0.01 + +type QuadSegment struct { + From, Ctrl, To f32.Point +} + +type StrokeQuad struct { + Contour uint32 + Quad QuadSegment +} + +type strokeState struct { + p0, p1 f32.Point // p0 is the start point, p1 the end point. + n0, n1 f32.Point // n0 is the normal vector at the start point, n1 at the end point. + r0, r1 float32 // r0 is the curvature at the start point, r1 at the end point. + ctl f32.Point // ctl is the control point of the quadratic Bézier segment. +} + +type StrokeQuads []StrokeQuad + +func (qs *StrokeQuads) setContour(n uint32) { + for i := range *qs { + (*qs)[i].Contour = n + } +} + +func (qs *StrokeQuads) pen() f32.Point { + return (*qs)[len(*qs)-1].Quad.To +} + +func (qs *StrokeQuads) lineTo(pt f32.Point) { + end := qs.pen() + *qs = append(*qs, StrokeQuad{ + Quad: QuadSegment{ + From: end, + Ctrl: end.Add(pt).Mul(0.5), + To: pt, + }, + }) +} + +func (qs *StrokeQuads) arc(f1, f2 f32.Point, angle float32) { + const segments = 16 + pen := qs.pen() + m := ArcTransform(pen, f1.Add(pen), f2.Add(pen), angle, segments) + for i := 0; i < segments; i++ { + p0 := qs.pen() + p1 := m.Transform(p0) + p2 := m.Transform(p1) + ctl := p1.Mul(2).Sub(p0.Add(p2).Mul(.5)) + *qs = append(*qs, StrokeQuad{ + Quad: QuadSegment{ + From: p0, Ctrl: ctl, To: p2, + }, + }) + } +} + +// split splits a slice of quads into slices of quads grouped +// by contours (ie: splitted at move-to boundaries). +func (qs StrokeQuads) split() []StrokeQuads { + if len(qs) == 0 { + return nil + } + + var ( + c uint32 + o []StrokeQuads + i = len(o) + ) + for _, q := range qs { + if q.Contour != c { + c = q.Contour + i = len(o) + o = append(o, StrokeQuads{}) + } + o[i] = append(o[i], q) + } + + return o +} + +func (qs StrokeQuads) stroke(stroke StrokeStyle) StrokeQuads { + var ( + o StrokeQuads + hw = 0.5 * stroke.Width + ) + + for _, ps := range qs.split() { + rhs, lhs := ps.offset(hw, stroke) + switch lhs { + case nil: + o = o.append(rhs) + default: + // Closed path. + // Inner path should go opposite direction to cancel outer path. + switch { + case ps.ccw(): + lhs = lhs.reverse() + o = o.append(rhs) + o = o.append(lhs) + default: + rhs = rhs.reverse() + o = o.append(lhs) + o = o.append(rhs) + } + } + } + + return o +} + +// offset returns the right-hand and left-hand sides of the path, offset by +// the half-width hw. +// The stroke handles how segments are joined and ends are capped. +func (qs StrokeQuads) offset(hw float32, stroke StrokeStyle) (rhs, lhs StrokeQuads) { + var ( + states []strokeState + beg = qs[0].Quad.From + end = qs[len(qs)-1].Quad.To + closed = beg == end + ) + for i := range qs { + q := qs[i].Quad + + var ( + n0 = strokePathNorm(q.From, q.Ctrl, q.To, 0, hw) + n1 = strokePathNorm(q.From, q.Ctrl, q.To, 1, hw) + r0 = strokePathCurv(q.From, q.Ctrl, q.To, 0) + r1 = strokePathCurv(q.From, q.Ctrl, q.To, 1) + ) + states = append(states, strokeState{ + p0: q.From, + p1: q.To, + n0: n0, + n1: n1, + r0: r0, + r1: r1, + ctl: q.Ctrl, + }) + } + + for i, state := range states { + rhs = rhs.append(strokeQuadBezier(state, +hw, strokeTolerance)) + lhs = lhs.append(strokeQuadBezier(state, -hw, strokeTolerance)) + + // join the current and next segments + if hasNext := i+1 < len(states); hasNext || closed { + var next strokeState + switch { + case hasNext: + next = states[i+1] + case closed: + next = states[0] + } + if state.n1 != next.n0 { + strokePathJoin(stroke, &rhs, &lhs, hw, state.p1, state.n1, next.n0, state.r1, next.r0) + } + } + } + + if closed { + rhs.close() + lhs.close() + return rhs, lhs + } + + qbeg := &states[0] + qend := &states[len(states)-1] + + // Default to counter-clockwise direction. + lhs = lhs.reverse() + strokePathCap(stroke, &rhs, hw, qend.p1, qend.n1) + + rhs = rhs.append(lhs) + strokePathCap(stroke, &rhs, hw, qbeg.p0, qbeg.n0.Mul(-1)) + + rhs.close() + + return rhs, nil +} + +func (qs *StrokeQuads) close() { + p0 := (*qs)[len(*qs)-1].Quad.To + p1 := (*qs)[0].Quad.From + + if p1 == p0 { + return + } + + *qs = append(*qs, StrokeQuad{ + Quad: QuadSegment{ + From: p0, + Ctrl: p0.Add(p1).Mul(0.5), + To: p1, + }, + }) +} + +// ccw returns whether the path is counter-clockwise. +func (qs StrokeQuads) ccw() bool { + // Use the Shoelace formula: + // https://en.wikipedia.org/wiki/Shoelace_formula + var area float32 + for _, ps := range qs.split() { + for i := 1; i < len(ps); i++ { + pi := ps[i].Quad.To + pj := ps[i-1].Quad.To + area += (pi.X - pj.X) * (pi.Y + pj.Y) + } + } + return area <= 0.0 +} + +func (qs StrokeQuads) reverse() StrokeQuads { + if len(qs) == 0 { + return nil + } + + ps := make(StrokeQuads, 0, len(qs)) + for i := range qs { + q := qs[len(qs)-1-i] + q.Quad.To, q.Quad.From = q.Quad.From, q.Quad.To + ps = append(ps, q) + } + + return ps +} + +func (qs StrokeQuads) append(ps StrokeQuads) StrokeQuads { + switch { + case len(ps) == 0: + return qs + case len(qs) == 0: + return ps + } + + // Consolidate quads and smooth out rounding errors. + // We need to also check for the strokeTolerance to correctly handle + // join/cap points or on-purpose disjoint quads. + p0 := qs[len(qs)-1].Quad.To + p1 := ps[0].Quad.From + if p0 != p1 && lenPt(p0.Sub(p1)) < strokeTolerance { + qs = append(qs, StrokeQuad{ + Quad: QuadSegment{ + From: p0, + Ctrl: p0.Add(p1).Mul(0.5), + To: p1, + }, + }) + } + return append(qs, ps...) +} + +func (q QuadSegment) Transform(t f32.Affine2D) QuadSegment { + q.From = t.Transform(q.From) + q.Ctrl = t.Transform(q.Ctrl) + q.To = t.Transform(q.To) + return q +} + +// strokePathNorm returns the normal vector at t. +func strokePathNorm(p0, p1, p2 f32.Point, t, d float32) f32.Point { + switch t { + case 0: + n := p1.Sub(p0) + if n.X == 0 && n.Y == 0 { + return f32.Point{} + } + n = rot90CW(n) + return normPt(n, d) + case 1: + n := p2.Sub(p1) + if n.X == 0 && n.Y == 0 { + return f32.Point{} + } + n = rot90CW(n) + return normPt(n, d) + } + panic("impossible") +} + +func rot90CW(p f32.Point) f32.Point { return f32.Pt(+p.Y, -p.X) } +func rot90CCW(p f32.Point) f32.Point { return f32.Pt(-p.Y, +p.X) } + +// cosPt returns the cosine of the opening angle between p and q. +func cosPt(p, q f32.Point) float32 { + np := math.Hypot(float64(p.X), float64(p.Y)) + nq := math.Hypot(float64(q.X), float64(q.Y)) + return dotPt(p, q) / float32(np*nq) +} + +func normPt(p f32.Point, l float32) f32.Point { + d := math.Hypot(float64(p.X), float64(p.Y)) + l64 := float64(l) + if math.Abs(d-l64) < 1e-10 { + return f32.Point{} + } + n := float32(l64 / d) + return f32.Point{X: p.X * n, Y: p.Y * n} +} + +func lenPt(p f32.Point) float32 { + return float32(math.Hypot(float64(p.X), float64(p.Y))) +} + +func dotPt(p, q f32.Point) float32 { + return p.X*q.X + p.Y*q.Y +} + +func perpDot(p, q f32.Point) float32 { + return p.X*q.Y - p.Y*q.X +} + +// strokePathCurv returns the curvature at t, along the quadratic Bézier +// curve defined by the triplet (beg, ctl, end). +func strokePathCurv(beg, ctl, end f32.Point, t float32) float32 { + var ( + d1p = quadBezierD1(beg, ctl, end, t) + d2p = quadBezierD2(beg, ctl, end, t) + + // Negative when bending right, ie: the curve is CW at this point. + a = float64(perpDot(d1p, d2p)) + ) + + // We check early that the segment isn't too line-like and + // save a costly call to math.Pow that will be discarded by dividing + // with a too small 'a'. + if math.Abs(a) < 1e-10 { + return float32(math.NaN()) + } + return float32(math.Pow(float64(d1p.X*d1p.X+d1p.Y*d1p.Y), 1.5) / a) +} + +// quadBezierSample returns the point on the Bézier curve at t. +// B(t) = (1-t)^2 P0 + 2(1-t)t P1 + t^2 P2 +func quadBezierSample(p0, p1, p2 f32.Point, t float32) f32.Point { + t1 := 1 - t + c0 := t1 * t1 + c1 := 2 * t1 * t + c2 := t * t + + o := p0.Mul(c0) + o = o.Add(p1.Mul(c1)) + o = o.Add(p2.Mul(c2)) + return o +} + +// quadBezierD1 returns the first derivative of the Bézier curve with respect to t. +// B'(t) = 2(1-t)(P1 - P0) + 2t(P2 - P1) +func quadBezierD1(p0, p1, p2 f32.Point, t float32) f32.Point { + p10 := p1.Sub(p0).Mul(2 * (1 - t)) + p21 := p2.Sub(p1).Mul(2 * t) + + return p10.Add(p21) +} + +// quadBezierD2 returns the second derivative of the Bézier curve with respect to t: +// B''(t) = 2(P2 - 2P1 + P0) +func quadBezierD2(p0, p1, p2 f32.Point, t float32) f32.Point { + p := p2.Sub(p1.Mul(2)).Add(p0) + return p.Mul(2) +} + +func strokeQuadBezier(state strokeState, d, flatness float32) StrokeQuads { + // Gio strokes are only quadratic Bézier curves, w/o any inflection point. + // So we just have to flatten them. + var qs StrokeQuads + return flattenQuadBezier(qs, state.p0, state.ctl, state.p1, d, flatness) +} + +// flattenQuadBezier splits a Bézier quadratic curve into linear sub-segments, +// themselves also encoded as Bézier (degenerate, flat) quadratic curves. +func flattenQuadBezier(qs StrokeQuads, p0, p1, p2 f32.Point, d, flatness float32) StrokeQuads { + var ( + t float32 + flat64 = float64(flatness) + ) + for t < 1 { + s2 := float64((p2.X-p0.X)*(p1.Y-p0.Y) - (p2.Y-p0.Y)*(p1.X-p0.X)) + den := math.Hypot(float64(p1.X-p0.X), float64(p1.Y-p0.Y)) + if s2*den == 0.0 { + break + } + + s2 /= den + t = 2.0 * float32(math.Sqrt(flat64/3.0/math.Abs(s2))) + if t >= 1.0 { + break + } + var q0, q1, q2 f32.Point + q0, q1, q2, p0, p1, p2 = quadBezierSplit(p0, p1, p2, t) + qs.addLine(q0, q1, q2, 0, d) + } + qs.addLine(p0, p1, p2, 1, d) + return qs +} + +func (qs *StrokeQuads) addLine(p0, ctrl, p1 f32.Point, t, d float32) { + + switch i := len(*qs); i { + case 0: + p0 = p0.Add(strokePathNorm(p0, ctrl, p1, 0, d)) + default: + // Address possible rounding errors and use previous point. + p0 = (*qs)[i-1].Quad.To + } + + p1 = p1.Add(strokePathNorm(p0, ctrl, p1, 1, d)) + + *qs = append(*qs, + StrokeQuad{ + Quad: QuadSegment{ + From: p0, + Ctrl: p0.Add(p1).Mul(0.5), + To: p1, + }, + }, + ) +} + +// quadInterp returns the interpolated point at t. +func quadInterp(p, q f32.Point, t float32) f32.Point { + return f32.Pt( + (1-t)*p.X+t*q.X, + (1-t)*p.Y+t*q.Y, + ) +} + +// quadBezierSplit returns the pair of triplets (from,ctrl,to) Bézier curve, +// split before (resp. after) the provided parametric t value. +func quadBezierSplit(p0, p1, p2 f32.Point, t float32) (f32.Point, f32.Point, f32.Point, f32.Point, f32.Point, f32.Point) { + + var ( + b0 = p0 + b1 = quadInterp(p0, p1, t) + b2 = quadBezierSample(p0, p1, p2, t) + + a0 = b2 + a1 = quadInterp(p1, p2, t) + a2 = p2 + ) + + return b0, b1, b2, a0, a1, a2 +} + +// strokePathJoin joins the two paths rhs and lhs, according to the provided +// stroke operation. +func strokePathJoin(stroke StrokeStyle, rhs, lhs *StrokeQuads, hw float32, pivot, n0, n1 f32.Point, r0, r1 float32) { + strokePathRoundJoin(rhs, lhs, hw, pivot, n0, n1, r0, r1) +} + +func strokePathRoundJoin(rhs, lhs *StrokeQuads, hw float32, pivot, n0, n1 f32.Point, r0, r1 float32) { + rp := pivot.Add(n1) + lp := pivot.Sub(n1) + cw := dotPt(rot90CW(n0), n1) >= 0.0 + switch { + case cw: + // Path bends to the right, ie. CW (or 180 degree turn). + c := pivot.Sub(lhs.pen()) + angle := -math.Acos(float64(cosPt(n0, n1))) + lhs.arc(c, c, float32(angle)) + lhs.lineTo(lp) // Add a line to accommodate for rounding errors. + rhs.lineTo(rp) + default: + // Path bends to the left, ie. CCW. + angle := math.Acos(float64(cosPt(n0, n1))) + c := pivot.Sub(rhs.pen()) + rhs.arc(c, c, float32(angle)) + rhs.lineTo(rp) // Add a line to accommodate for rounding errors. + lhs.lineTo(lp) + } +} + +// strokePathCap caps the provided path qs, according to the provided stroke operation. +func strokePathCap(stroke StrokeStyle, qs *StrokeQuads, hw float32, pivot, n0 f32.Point) { + strokePathRoundCap(qs, hw, pivot, n0) +} + +// strokePathRoundCap caps the start or end of a path with a round cap. +func strokePathRoundCap(qs *StrokeQuads, hw float32, pivot, n0 f32.Point) { + c := pivot.Sub(qs.pen()) + qs.arc(c, c, math.Pi) +} + +// ArcTransform computes a transformation that can be used for generating quadratic bézier +// curve approximations for an arc. +// +// The math is extracted from the following paper: +// "Drawing an elliptical arc using polylines, quadratic or +// cubic Bezier curves", L. Maisonobe +// An electronic version may be found at: +// http://spaceroots.org/documents/ellipse/elliptical-arc.pdf +func ArcTransform(p, f1, f2 f32.Point, angle float32, segments int) f32.Affine2D { + var rx, ry, alpha float64 + if f1 == f2 { + // degenerate case of a circle. + rx = dist(f1, p) + ry = rx + } else { + // semi-major axis: 2a = |PF1| + |PF2| + a := 0.5 * (dist(f1, p) + dist(f2, p)) + // semi-minor axis: c^2 = a^2 - b^2 (c: focal distance) + c := dist(f1, f2) * 0.5 + b := math.Sqrt(a*a - c*c) + switch { + case a > b: + rx = a + ry = b + default: + rx = b + ry = a + } + if f1.X == f2.X { + // special case of a "vertical" ellipse. + alpha = math.Pi / 2 + if f1.Y < f2.Y { + alpha = -alpha + } + } else { + x := float64(f1.X-f2.X) * 0.5 + if x < 0 { + x = -x + } + alpha = math.Acos(x / c) + } + } + + var ( + θ = angle / float32(segments) + ref f32.Affine2D // transform from absolute frame to ellipse-based one + rot f32.Affine2D // rotation matrix for each segment + inv f32.Affine2D // transform from ellipse-based frame to absolute one + ) + center := f32.Point{ + X: 0.5 * (f1.X + f2.X), + Y: 0.5 * (f1.Y + f2.Y), + } + ref = ref.Offset(f32.Point{}.Sub(center)) + ref = ref.Rotate(f32.Point{}, float32(-alpha)) + ref = ref.Scale(f32.Point{}, f32.Point{ + X: float32(1 / rx), + Y: float32(1 / ry), + }) + inv = ref.Invert() + rot = rot.Rotate(f32.Point{}, 0.5*θ) + + // Instead of invoking math.Sincos for every segment, compute a rotation + // matrix once and apply for each segment. + // Before applying the rotation matrix rot, transform the coordinates + // to a frame centered to the ellipse (and warped into a unit circle), then rotate. + // Finally, transform back into the original frame. + return inv.Mul(rot).Mul(ref) +} + +func dist(p1, p2 f32.Point) float64 { + var ( + x1 = float64(p1.X) + y1 = float64(p1.Y) + x2 = float64(p2.X) + y2 = float64(p2.Y) + dx = x2 - x1 + dy = y2 - y1 + ) + return math.Hypot(dx, dy) +} + +func StrokePathCommands(style StrokeStyle, scene []byte) StrokeQuads { + quads := decodeToStrokeQuads(scene) + return quads.stroke(style) +} + +// decodeToStrokeQuads decodes scene commands to quads ready to stroke. +func decodeToStrokeQuads(pathData []byte) StrokeQuads { + quads := make(StrokeQuads, 0, 2*len(pathData)/(scene.CommandSize+4)) + for len(pathData) >= scene.CommandSize+4 { + contour := binary.LittleEndian.Uint32(pathData) + cmd := ops.DecodeCommand(pathData[4:]) + switch cmd.Op() { + case scene.OpLine: + var q QuadSegment + q.From, q.To = scene.DecodeLine(cmd) + q.Ctrl = q.From.Add(q.To).Mul(.5) + quad := StrokeQuad{ + Contour: contour, + Quad: q, + } + quads = append(quads, quad) + case scene.OpGap: + // Ignore gaps for strokes. + case scene.OpQuad: + var q QuadSegment + q.From, q.Ctrl, q.To = scene.DecodeQuad(cmd) + quad := StrokeQuad{ + Contour: contour, + Quad: q, + } + quads = append(quads, quad) + case scene.OpCubic: + for _, q := range SplitCubic(scene.DecodeCubic(cmd)) { + quad := StrokeQuad{ + Contour: contour, + Quad: q, + } + quads = append(quads, quad) + } + default: + panic("unsupported scene command") + } + pathData = pathData[scene.CommandSize+4:] + } + return quads +} + +func SplitCubic(from, ctrl0, ctrl1, to f32.Point) []QuadSegment { + quads := make([]QuadSegment, 0, 10) + // Set the maximum distance proportionally to the longest side + // of the bounding rectangle. + hull := f32.Rectangle{ + Min: from, + Max: ctrl0, + }.Canon().Union(f32.Rectangle{ + Min: ctrl1, + Max: to, + }.Canon()) + l := hull.Dx() + if h := hull.Dy(); h > l { + l = h + } + approxCubeTo(&quads, 0, l*0.001, from, ctrl0, ctrl1, to) + return quads +} + +// approxCubeTo approximates a cubic Bézier by a series of quadratic +// curves. +func approxCubeTo(quads *[]QuadSegment, splits int, maxDist float32, from, ctrl0, ctrl1, to f32.Point) int { + // The idea is from + // https://caffeineowl.com/graphics/2d/vectorial/cubic2quad01.html + // where a quadratic approximates a cubic by eliminating its t³ term + // from its polynomial expression anchored at the starting point: + // + // P(t) = pen + 3t(ctrl0 - pen) + 3t²(ctrl1 - 2ctrl0 + pen) + t³(to - 3ctrl1 + 3ctrl0 - pen) + // + // The control point for the new quadratic Q1 that shares starting point, pen, with P is + // + // C1 = (3ctrl0 - pen)/2 + // + // The reverse cubic anchored at the end point has the polynomial + // + // P'(t) = to + 3t(ctrl1 - to) + 3t²(ctrl0 - 2ctrl1 + to) + t³(pen - 3ctrl0 + 3ctrl1 - to) + // + // The corresponding quadratic Q2 that shares the end point, to, with P has control + // point + // + // C2 = (3ctrl1 - to)/2 + // + // The combined quadratic Bézier, Q, shares both start and end points with its cubic + // and use the midpoint between the two curves Q1 and Q2 as control point: + // + // C = (3ctrl0 - pen + 3ctrl1 - to)/4 + c := ctrl0.Mul(3).Sub(from).Add(ctrl1.Mul(3)).Sub(to).Mul(1.0 / 4.0) + const maxSplits = 32 + if splits >= maxSplits { + *quads = append(*quads, QuadSegment{From: from, Ctrl: c, To: to}) + return splits + } + // The maximum distance between the cubic P and its approximation Q given t + // can be shown to be + // + // d = sqrt(3)/36*|to - 3ctrl1 + 3ctrl0 - pen| + // + // To save a square root, compare d² with the squared tolerance. + v := to.Sub(ctrl1.Mul(3)).Add(ctrl0.Mul(3)).Sub(from) + d2 := (v.X*v.X + v.Y*v.Y) * 3 / (36 * 36) + if d2 <= maxDist*maxDist { + *quads = append(*quads, QuadSegment{From: from, Ctrl: c, To: to}) + return splits + } + // De Casteljau split the curve and approximate the halves. + t := float32(0.5) + c0 := from.Add(ctrl0.Sub(from).Mul(t)) + c1 := ctrl0.Add(ctrl1.Sub(ctrl0).Mul(t)) + c2 := ctrl1.Add(to.Sub(ctrl1).Mul(t)) + c01 := c0.Add(c1.Sub(c0).Mul(t)) + c12 := c1.Add(c2.Sub(c1).Mul(t)) + c0112 := c01.Add(c12.Sub(c01).Mul(t)) + splits++ + splits = approxCubeTo(quads, splits, maxDist, from, c0, c01, c0112) + splits = approxCubeTo(quads, splits, maxDist, c0112, c12, c2, to) + return splits +} diff --git a/vendor/gioui.org/internal/unsafe/unsafe.go b/vendor/gioui.org/internal/unsafe/unsafe.go deleted file mode 100644 index 5353144..0000000 --- a/vendor/gioui.org/internal/unsafe/unsafe.go +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: Unlicense OR MIT - -package unsafe - -import ( - "reflect" - "unsafe" -) - -// BytesView returns a byte slice view of a slice. -func BytesView(s interface{}) []byte { - v := reflect.ValueOf(s) - first := v.Index(0) - sz := int(first.Type().Size()) - return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Data: uintptr(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(first.UnsafeAddr())))), - Len: v.Len() * sz, - Cap: v.Cap() * sz, - })) -} - -// SliceOf returns a slice from a (native) pointer. -func SliceOf(s uintptr) []byte { - if s == 0 { - return nil - } - sh := reflect.SliceHeader{ - Data: s, - Len: 1 << 30, - Cap: 1 << 30, - } - return *(*[]byte)(unsafe.Pointer(&sh)) -} - -// GoString convert a NUL-terminated C string -// to a Go string. -func GoString(s []byte) string { - i := 0 - for { - if s[i] == 0 { - break - } - i++ - } - return string(s[:i]) -} diff --git a/vendor/gioui.org/internal/vk/vulkan.go b/vendor/gioui.org/internal/vk/vulkan.go new file mode 100644 index 0000000..f210d40 --- /dev/null +++ b/vendor/gioui.org/internal/vk/vulkan.go @@ -0,0 +1,2081 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +//go:build linux || freebsd +// +build linux freebsd + +package vk + +/* +#cgo linux freebsd LDFLAGS: -ldl +#cgo freebsd CFLAGS: -I/usr/local/include +#cgo CFLAGS: -Werror -Werror=return-type + +#define VK_NO_PROTOTYPES 1 +#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; +#include <vulkan/vulkan.h> +#define __USE_GNU +#include <dlfcn.h> +#include <stdlib.h> + +static VkResult vkCreateInstance(PFN_vkCreateInstance f, VkInstanceCreateInfo pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) { + return f(&pCreateInfo, pAllocator, pInstance); +} + +static void vkDestroyInstance(PFN_vkDestroyInstance f, VkInstance instance, const VkAllocationCallbacks *pAllocator) { + f(instance, pAllocator); +} + +static VkResult vkEnumeratePhysicalDevices(PFN_vkEnumeratePhysicalDevices f, VkInstance instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices) { + return f(instance, pPhysicalDeviceCount, pPhysicalDevices); +} + +static void vkGetPhysicalDeviceQueueFamilyProperties(PFN_vkGetPhysicalDeviceQueueFamilyProperties f, VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties *pQueueFamilyProperties) { + f(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties); +} + +static void vkGetPhysicalDeviceFormatProperties(PFN_vkGetPhysicalDeviceFormatProperties f, VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties *pFormatProperties) { + f(physicalDevice, format, pFormatProperties); +} + +static VkResult vkCreateDevice(PFN_vkCreateDevice f, VkPhysicalDevice physicalDevice, VkDeviceCreateInfo pCreateInfo, VkDeviceQueueCreateInfo qinf, const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) { + pCreateInfo.pQueueCreateInfos = &qinf; + return f(physicalDevice, &pCreateInfo, pAllocator, pDevice); +} + +static void vkDestroyDevice(PFN_vkDestroyDevice f, VkDevice device, const VkAllocationCallbacks *pAllocator) { + f(device, pAllocator); +} + +static void vkGetDeviceQueue(PFN_vkGetDeviceQueue f, VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) { + f(device, queueFamilyIndex, queueIndex, pQueue); +} + +static VkResult vkCreateImageView(PFN_vkCreateImageView f, VkDevice device, const VkImageViewCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImageView *pView) { + return f(device, pCreateInfo, pAllocator, pView); +} + +static void vkDestroyImageView(PFN_vkDestroyImageView f, VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) { + f(device, imageView, pAllocator); +} + +static VkResult vkCreateFramebuffer(PFN_vkCreateFramebuffer f, VkDevice device, VkFramebufferCreateInfo pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) { + return f(device, &pCreateInfo, pAllocator, pFramebuffer); +} + +static void vkDestroyFramebuffer(PFN_vkDestroyFramebuffer f, VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) { + f(device, framebuffer, pAllocator); +} + +static VkResult vkDeviceWaitIdle(PFN_vkDeviceWaitIdle f, VkDevice device) { + return f(device); +} + +static VkResult vkQueueWaitIdle(PFN_vkQueueWaitIdle f, VkQueue queue) { + return f(queue); +} + +static VkResult vkCreateSemaphore(PFN_vkCreateSemaphore f, VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) { + return f(device, pCreateInfo, pAllocator, pSemaphore); +} + +static void vkDestroySemaphore(PFN_vkDestroySemaphore f, VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) { + f(device, semaphore, pAllocator); +} + +static VkResult vkCreateRenderPass(PFN_vkCreateRenderPass f, VkDevice device, VkRenderPassCreateInfo pCreateInfo, VkSubpassDescription subpassInf, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) { + pCreateInfo.pSubpasses = &subpassInf; + return f(device, &pCreateInfo, pAllocator, pRenderPass); +} + +static void vkDestroyRenderPass(PFN_vkDestroyRenderPass f, VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) { + f(device, renderPass, pAllocator); +} + +static VkResult vkCreateCommandPool(PFN_vkCreateCommandPool f, VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool) { + return f(device, pCreateInfo, pAllocator, pCommandPool); +} + +static void vkDestroyCommandPool(PFN_vkDestroyCommandPool f, VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) { + f(device, commandPool, pAllocator); +} + +static VkResult vkAllocateCommandBuffers(PFN_vkAllocateCommandBuffers f, VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo, VkCommandBuffer *pCommandBuffers) { + return f(device, pAllocateInfo, pCommandBuffers); +} + +static void vkFreeCommandBuffers(PFN_vkFreeCommandBuffers f, VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers) { + f(device, commandPool, commandBufferCount, pCommandBuffers); +} + +static VkResult vkBeginCommandBuffer(PFN_vkBeginCommandBuffer f, VkCommandBuffer commandBuffer, VkCommandBufferBeginInfo pBeginInfo) { + return f(commandBuffer, &pBeginInfo); +} + +static VkResult vkEndCommandBuffer(PFN_vkEndCommandBuffer f, VkCommandBuffer commandBuffer) { + return f(commandBuffer); +} + +static VkResult vkQueueSubmit(PFN_vkQueueSubmit f, VkQueue queue, VkSubmitInfo pSubmits, VkFence fence) { + return f(queue, 1, &pSubmits, fence); +} + +static void vkCmdBeginRenderPass(PFN_vkCmdBeginRenderPass f, VkCommandBuffer commandBuffer, VkRenderPassBeginInfo pRenderPassBegin, VkSubpassContents contents) { + f(commandBuffer, &pRenderPassBegin, contents); +} + +static void vkCmdEndRenderPass(PFN_vkCmdEndRenderPass f, VkCommandBuffer commandBuffer) { + f(commandBuffer); +} + +static void vkCmdCopyBuffer(PFN_vkCmdCopyBuffer f, VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy *pRegions) { + f(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions); +} + +static void vkCmdCopyBufferToImage(PFN_vkCmdCopyBufferToImage f, VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy *pRegions) { + f(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions); +} + +static void vkCmdPipelineBarrier(PFN_vkCmdPipelineBarrier f, VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) { + f(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); +} + +static void vkCmdPushConstants(PFN_vkCmdPushConstants f, VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void *pValues) { + f(commandBuffer, layout, stageFlags, offset, size, pValues); +} + +static void vkCmdBindPipeline(PFN_vkCmdBindPipeline f, VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) { + f(commandBuffer, pipelineBindPoint, pipeline); +} + +static void vkCmdBindVertexBuffers(PFN_vkCmdBindVertexBuffers f, VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) { + f(commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets); +} + +static void vkCmdSetViewport(PFN_vkCmdSetViewport f, VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport *pViewports) { + f(commandBuffer, firstViewport, viewportCount, pViewports); +} + +static void vkCmdBindIndexBuffer(PFN_vkCmdBindIndexBuffer f, VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) { + f(commandBuffer, buffer, offset, indexType); +} + +static void vkCmdDraw(PFN_vkCmdDraw f, VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) { + f(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance); +} + +static void vkCmdDrawIndexed(PFN_vkCmdDrawIndexed f, VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) { + f(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); +} + +static void vkCmdBindDescriptorSets(PFN_vkCmdBindDescriptorSets f, VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t *pDynamicOffsets) { + f(commandBuffer, pipelineBindPoint, layout, firstSet, descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets); +} + +static void vkCmdCopyImageToBuffer(PFN_vkCmdCopyImageToBuffer f, VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) { + f(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions); +} + +static void vkCmdDispatch(PFN_vkCmdDispatch f, VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) { + f(commandBuffer, groupCountX, groupCountY, groupCountZ); +} + +static VkResult vkCreateImage(PFN_vkCreateImage f, VkDevice device, const VkImageCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImage *pImage) { + return f(device, pCreateInfo, pAllocator, pImage); +} + +static void vkDestroyImage(PFN_vkDestroyImage f, VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) { + f(device, image, pAllocator); +} + +static void vkGetImageMemoryRequirements(PFN_vkGetImageMemoryRequirements f, VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) { + f(device, image, pMemoryRequirements); +} + +static VkResult vkAllocateMemory(PFN_vkAllocateMemory f, VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo, const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) { + return f(device, pAllocateInfo, pAllocator, pMemory); +} + +static VkResult vkBindImageMemory(PFN_vkBindImageMemory f, VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset) { + return f(device, image, memory, memoryOffset); +} + +static void vkFreeMemory(PFN_vkFreeMemory f, VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks *pAllocator) { + f(device, memory, pAllocator); +} + +static void vkGetPhysicalDeviceMemoryProperties(PFN_vkGetPhysicalDeviceMemoryProperties f, VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties *pMemoryProperties) { + f(physicalDevice, pMemoryProperties); +} + +static VkResult vkCreateSampler(PFN_vkCreateSampler f,VkDevice device, const VkSamplerCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) { + return f(device, pCreateInfo, pAllocator, pSampler); +} + +static void vkDestroySampler(PFN_vkDestroySampler f, VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) { + f(device, sampler, pAllocator); +} + +static VkResult vkCreateBuffer(PFN_vkCreateBuffer f, VkDevice device, const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) { + return f(device, pCreateInfo, pAllocator, pBuffer); +} + +static void vkDestroyBuffer(PFN_vkDestroyBuffer f, VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) { + f(device, buffer, pAllocator); +} + +static void vkGetBufferMemoryRequirements(PFN_vkGetBufferMemoryRequirements f, VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements) { + f(device, buffer, pMemoryRequirements); +} + +static VkResult vkBindBufferMemory(PFN_vkBindBufferMemory f, VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset) { + return f(device, buffer, memory, memoryOffset); +} + +static VkResult vkCreateShaderModule(PFN_vkCreateShaderModule f, VkDevice device, VkShaderModuleCreateInfo pCreateInfo, const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) { + return f(device, &pCreateInfo, pAllocator, pShaderModule); +} + +static void vkDestroyShaderModule(PFN_vkDestroyShaderModule f, VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks *pAllocator) { + f(device, shaderModule, pAllocator); +} + +static VkResult vkCreateGraphicsPipelines(PFN_vkCreateGraphicsPipelines f, VkDevice device, VkPipelineCache pipelineCache, VkGraphicsPipelineCreateInfo pCreateInfo, VkPipelineDynamicStateCreateInfo dynInf, VkPipelineColorBlendStateCreateInfo blendInf, VkPipelineVertexInputStateCreateInfo vertexInf, VkPipelineViewportStateCreateInfo viewportInf, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) { + pCreateInfo.pDynamicState = &dynInf; + pCreateInfo.pViewportState = &viewportInf; + pCreateInfo.pColorBlendState = &blendInf; + pCreateInfo.pVertexInputState = &vertexInf; + return f(device, pipelineCache, 1, &pCreateInfo, pAllocator, pPipelines); +} + +static void vkDestroyPipeline(PFN_vkDestroyPipeline f, VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) { + f(device, pipeline, pAllocator); +} + +static VkResult vkCreatePipelineLayout(PFN_vkCreatePipelineLayout f, VkDevice device, VkPipelineLayoutCreateInfo pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) { + return f(device, &pCreateInfo, pAllocator, pPipelineLayout); +} + +static void vkDestroyPipelineLayout(PFN_vkDestroyPipelineLayout f, VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks *pAllocator) { + f(device, pipelineLayout, pAllocator); +} + +static VkResult vkCreateDescriptorSetLayout(PFN_vkCreateDescriptorSetLayout f, VkDevice device, VkDescriptorSetLayoutCreateInfo pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout) { + return f(device, &pCreateInfo, pAllocator, pSetLayout); +} + +static void vkDestroyDescriptorSetLayout(PFN_vkDestroyDescriptorSetLayout f, VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks *pAllocator) { + f(device, descriptorSetLayout, pAllocator); +} + +static VkResult vkMapMemory(PFN_vkMapMemory f, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void **ppData) { + return f(device, memory, offset, size, flags, ppData); +} + +static void vkUnmapMemory(PFN_vkUnmapMemory f, VkDevice device, VkDeviceMemory memory) { + f(device, memory); +} + +static VkResult vkResetCommandBuffer(PFN_vkResetCommandBuffer f, VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) { + return f(commandBuffer, flags); +} + +static VkResult vkCreateDescriptorPool(PFN_vkCreateDescriptorPool f, VkDevice device, VkDescriptorPoolCreateInfo pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool) { + return f(device, &pCreateInfo, pAllocator, pDescriptorPool); +} + +static void vkDestroyDescriptorPool(PFN_vkDestroyDescriptorPool f, VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks *pAllocator) { + f(device, descriptorPool, pAllocator); +} + +static VkResult vkAllocateDescriptorSets(PFN_vkAllocateDescriptorSets f, VkDevice device, VkDescriptorSetAllocateInfo pAllocateInfo, VkDescriptorSet *pDescriptorSets) { + return f(device, &pAllocateInfo, pDescriptorSets); +} + +static VkResult vkFreeDescriptorSets(PFN_vkFreeDescriptorSets f, VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets) { + return f(device, descriptorPool, descriptorSetCount, pDescriptorSets); +} + +static void vkUpdateDescriptorSets(PFN_vkUpdateDescriptorSets f, VkDevice device, VkWriteDescriptorSet pDescriptorWrite, uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies) { + f(device, 1, &pDescriptorWrite, descriptorCopyCount, pDescriptorCopies); +} + +static VkResult vkResetDescriptorPool(PFN_vkResetDescriptorPool f, VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) { + return f(device, descriptorPool, flags); +} + +static void vkCmdCopyImage(PFN_vkCmdCopyImage f, VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy *pRegions) { + f(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions); +} + +static VkResult vkCreateComputePipelines(PFN_vkCreateComputePipelines f, VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) { + return f(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); +} + +static VkResult vkCreateFence(PFN_vkCreateFence f, VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence) { + return f(device, pCreateInfo, pAllocator, pFence); +} + +static void vkDestroyFence(PFN_vkDestroyFence f, VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) { + f(device, fence, pAllocator); +} + +static VkResult vkWaitForFences(PFN_vkWaitForFences f, VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout) { + return f(device, fenceCount, pFences, waitAll, timeout); +} + +static VkResult vkResetFences(PFN_vkResetFences f, VkDevice device, uint32_t fenceCount, const VkFence *pFences) { + return f(device, fenceCount, pFences); +} + +static void vkGetPhysicalDeviceProperties(PFN_vkGetPhysicalDeviceProperties f, VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties) { + f(physicalDevice, pProperties); +} + +static VkResult vkGetPhysicalDeviceSurfaceSupportKHR(PFN_vkGetPhysicalDeviceSurfaceSupportKHR f, VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32 *pSupported) { + return f(physicalDevice, queueFamilyIndex, surface, pSupported); +} + +static void vkDestroySurfaceKHR(PFN_vkDestroySurfaceKHR f, VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator) { + f(instance, surface, pAllocator); +} + +static VkResult vkGetPhysicalDeviceSurfaceFormatsKHR(PFN_vkGetPhysicalDeviceSurfaceFormatsKHR f, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pSurfaceFormatCount, VkSurfaceFormatKHR *pSurfaceFormats) { + return f(physicalDevice, surface, pSurfaceFormatCount, pSurfaceFormats); +} + +static VkResult vkGetPhysicalDeviceSurfacePresentModesKHR(PFN_vkGetPhysicalDeviceSurfacePresentModesKHR f, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes) { + return f(physicalDevice, surface, pPresentModeCount, pPresentModes); +} + +static VkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR(PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR f, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) { + return f(physicalDevice, surface, pSurfaceCapabilities); +} + +static VkResult vkCreateSwapchainKHR(PFN_vkCreateSwapchainKHR f, VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) { + return f(device, pCreateInfo, pAllocator, pSwapchain); +} + +static void vkDestroySwapchainKHR(PFN_vkDestroySwapchainKHR f, VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) { + f(device, swapchain, pAllocator); +} + +static VkResult vkGetSwapchainImagesKHR(PFN_vkGetSwapchainImagesKHR f, VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) { + return f(device, swapchain, pSwapchainImageCount, pSwapchainImages); +} + +// indexAndResult holds both an integer and a result returned by value, to +// avoid Go heap allocation of the integer with Vulkan's return style. +struct intAndResult { + uint32_t uint; + VkResult res; +}; + +static struct intAndResult vkAcquireNextImageKHR(PFN_vkAcquireNextImageKHR f, VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence) { + struct intAndResult res; + res.res = f(device, swapchain, timeout, semaphore, fence, &res.uint); + return res; +} + +static VkResult vkQueuePresentKHR(PFN_vkQueuePresentKHR f, VkQueue queue, const VkPresentInfoKHR pPresentInfo) { + return f(queue, &pPresentInfo); +} +*/ +import "C" +import ( + "errors" + "fmt" + "image" + "math" + "reflect" + "runtime" + "sync" + "unsafe" +) + +type ( + AttachmentLoadOp = C.VkAttachmentLoadOp + AccessFlags = C.VkAccessFlags + BlendFactor = C.VkBlendFactor + Buffer = C.VkBuffer + BufferImageCopy = C.VkBufferImageCopy + BufferMemoryBarrier = C.VkBufferMemoryBarrier + BufferUsageFlags = C.VkBufferUsageFlags + CommandPool = C.VkCommandPool + CommandBuffer = C.VkCommandBuffer + DependencyFlags = C.VkDependencyFlags + DescriptorPool = C.VkDescriptorPool + DescriptorPoolSize = C.VkDescriptorPoolSize + DescriptorSet = C.VkDescriptorSet + DescriptorSetLayout = C.VkDescriptorSetLayout + DescriptorType = C.VkDescriptorType + Device = C.VkDevice + DeviceMemory = C.VkDeviceMemory + DeviceSize = C.VkDeviceSize + Fence = C.VkFence + Queue = C.VkQueue + IndexType = C.VkIndexType + Image = C.VkImage + ImageCopy = C.VkImageCopy + ImageLayout = C.VkImageLayout + ImageMemoryBarrier = C.VkImageMemoryBarrier + ImageUsageFlags = C.VkImageUsageFlags + ImageView = C.VkImageView + Instance = C.VkInstance + Filter = C.VkFilter + Format = C.VkFormat + FormatFeatureFlags = C.VkFormatFeatureFlags + Framebuffer = C.VkFramebuffer + MemoryBarrier = C.VkMemoryBarrier + MemoryPropertyFlags = C.VkMemoryPropertyFlags + Pipeline = C.VkPipeline + PipelineBindPoint = C.VkPipelineBindPoint + PipelineLayout = C.VkPipelineLayout + PipelineStageFlags = C.VkPipelineStageFlags + PhysicalDevice = C.VkPhysicalDevice + PrimitiveTopology = C.VkPrimitiveTopology + PushConstantRange = C.VkPushConstantRange + QueueFamilyProperties = C.VkQueueFamilyProperties + QueueFlags = C.VkQueueFlags + RenderPass = C.VkRenderPass + Sampler = C.VkSampler + SamplerMipmapMode = C.VkSamplerMipmapMode + Semaphore = C.VkSemaphore + ShaderModule = C.VkShaderModule + ShaderStageFlags = C.VkShaderStageFlags + SubpassDependency = C.VkSubpassDependency + Viewport = C.VkViewport + WriteDescriptorSet = C.VkWriteDescriptorSet + + Surface = C.VkSurfaceKHR + SurfaceCapabilities = C.VkSurfaceCapabilitiesKHR + + Swapchain = C.VkSwapchainKHR +) + +type VertexInputBindingDescription struct { + Binding int + Stride int +} + +type VertexInputAttributeDescription struct { + Location int + Binding int + Format Format + Offset int +} + +type DescriptorSetLayoutBinding struct { + Binding int + DescriptorType DescriptorType + StageFlags ShaderStageFlags +} + +type Error C.VkResult + +const ( + FORMAT_R8G8B8A8_UNORM Format = C.VK_FORMAT_R8G8B8A8_UNORM + FORMAT_B8G8R8A8_SRGB Format = C.VK_FORMAT_B8G8R8A8_SRGB + FORMAT_R8G8B8A8_SRGB Format = C.VK_FORMAT_R8G8B8A8_SRGB + FORMAT_R16_SFLOAT Format = C.VK_FORMAT_R16_SFLOAT + FORMAT_R32_SFLOAT Format = C.VK_FORMAT_R32_SFLOAT + FORMAT_R32G32_SFLOAT Format = C.VK_FORMAT_R32G32_SFLOAT + FORMAT_R32G32B32_SFLOAT Format = C.VK_FORMAT_R32G32B32_SFLOAT + FORMAT_R32G32B32A32_SFLOAT Format = C.VK_FORMAT_R32G32B32A32_SFLOAT + + FORMAT_FEATURE_COLOR_ATTACHMENT_BIT FormatFeatureFlags = C.VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT + FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT FormatFeatureFlags = C.VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT + FORMAT_FEATURE_SAMPLED_IMAGE_BIT FormatFeatureFlags = C.VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT + + IMAGE_USAGE_SAMPLED_BIT ImageUsageFlags = C.VK_IMAGE_USAGE_SAMPLED_BIT + IMAGE_USAGE_COLOR_ATTACHMENT_BIT ImageUsageFlags = C.VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT + IMAGE_USAGE_STORAGE_BIT ImageUsageFlags = C.VK_IMAGE_USAGE_STORAGE_BIT + IMAGE_USAGE_TRANSFER_DST_BIT ImageUsageFlags = C.VK_IMAGE_USAGE_TRANSFER_DST_BIT + IMAGE_USAGE_TRANSFER_SRC_BIT ImageUsageFlags = C.VK_IMAGE_USAGE_TRANSFER_SRC_BIT + + FILTER_NEAREST Filter = C.VK_FILTER_NEAREST + FILTER_LINEAR Filter = C.VK_FILTER_LINEAR + + ATTACHMENT_LOAD_OP_CLEAR AttachmentLoadOp = C.VK_ATTACHMENT_LOAD_OP_CLEAR + ATTACHMENT_LOAD_OP_DONT_CARE AttachmentLoadOp = C.VK_ATTACHMENT_LOAD_OP_DONT_CARE + ATTACHMENT_LOAD_OP_LOAD AttachmentLoadOp = C.VK_ATTACHMENT_LOAD_OP_LOAD + + IMAGE_LAYOUT_UNDEFINED ImageLayout = C.VK_IMAGE_LAYOUT_UNDEFINED + IMAGE_LAYOUT_PRESENT_SRC_KHR ImageLayout = C.VK_IMAGE_LAYOUT_PRESENT_SRC_KHR + IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ImageLayout = C.VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ImageLayout = C.VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ImageLayout = C.VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ImageLayout = C.VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL + IMAGE_LAYOUT_GENERAL ImageLayout = C.VK_IMAGE_LAYOUT_GENERAL + + BUFFER_USAGE_TRANSFER_DST_BIT BufferUsageFlags = C.VK_BUFFER_USAGE_TRANSFER_DST_BIT + BUFFER_USAGE_TRANSFER_SRC_BIT BufferUsageFlags = C.VK_BUFFER_USAGE_TRANSFER_SRC_BIT + BUFFER_USAGE_UNIFORM_BUFFER_BIT BufferUsageFlags = C.VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT + BUFFER_USAGE_STORAGE_BUFFER_BIT BufferUsageFlags = C.VK_BUFFER_USAGE_STORAGE_BUFFER_BIT + BUFFER_USAGE_INDEX_BUFFER_BIT BufferUsageFlags = C.VK_BUFFER_USAGE_INDEX_BUFFER_BIT + BUFFER_USAGE_VERTEX_BUFFER_BIT BufferUsageFlags = C.VK_BUFFER_USAGE_VERTEX_BUFFER_BIT + + ERROR_OUT_OF_DATE_KHR = Error(C.VK_ERROR_OUT_OF_DATE_KHR) + ERROR_SURFACE_LOST_KHR = Error(C.VK_ERROR_SURFACE_LOST_KHR) + ERROR_DEVICE_LOST = Error(C.VK_ERROR_DEVICE_LOST) + SUBOPTIMAL_KHR = Error(C.VK_SUBOPTIMAL_KHR) + + BLEND_FACTOR_ZERO BlendFactor = C.VK_BLEND_FACTOR_ZERO + BLEND_FACTOR_ONE BlendFactor = C.VK_BLEND_FACTOR_ONE + BLEND_FACTOR_ONE_MINUS_SRC_ALPHA BlendFactor = C.VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA + BLEND_FACTOR_DST_COLOR BlendFactor = C.VK_BLEND_FACTOR_DST_COLOR + + PRIMITIVE_TOPOLOGY_TRIANGLE_LIST PrimitiveTopology = C.VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST + PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP PrimitiveTopology = C.VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP + + SHADER_STAGE_VERTEX_BIT ShaderStageFlags = C.VK_SHADER_STAGE_VERTEX_BIT + SHADER_STAGE_FRAGMENT_BIT ShaderStageFlags = C.VK_SHADER_STAGE_FRAGMENT_BIT + SHADER_STAGE_COMPUTE_BIT ShaderStageFlags = C.VK_SHADER_STAGE_COMPUTE_BIT + + DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER DescriptorType = C.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER + DESCRIPTOR_TYPE_UNIFORM_BUFFER DescriptorType = C.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER + DESCRIPTOR_TYPE_STORAGE_BUFFER DescriptorType = C.VK_DESCRIPTOR_TYPE_STORAGE_BUFFER + DESCRIPTOR_TYPE_STORAGE_IMAGE DescriptorType = C.VK_DESCRIPTOR_TYPE_STORAGE_IMAGE + + MEMORY_PROPERTY_DEVICE_LOCAL_BIT MemoryPropertyFlags = C.VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT + MEMORY_PROPERTY_HOST_VISIBLE_BIT MemoryPropertyFlags = C.VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT + MEMORY_PROPERTY_HOST_COHERENT_BIT MemoryPropertyFlags = C.VK_MEMORY_PROPERTY_HOST_COHERENT_BIT + + DEPENDENCY_BY_REGION_BIT DependencyFlags = C.VK_DEPENDENCY_BY_REGION_BIT + + PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT + PIPELINE_STAGE_TRANSFER_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_TRANSFER_BIT + PIPELINE_STAGE_FRAGMENT_SHADER_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT + PIPELINE_STAGE_COMPUTE_SHADER_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT + PIPELINE_STAGE_TOP_OF_PIPE_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT + PIPELINE_STAGE_HOST_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_HOST_BIT + PIPELINE_STAGE_VERTEX_INPUT_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_VERTEX_INPUT_BIT + PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT PipelineStageFlags = C.VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT + + ACCESS_MEMORY_READ_BIT AccessFlags = C.VK_ACCESS_MEMORY_READ_BIT + ACCESS_MEMORY_WRITE_BIT AccessFlags = C.VK_ACCESS_MEMORY_WRITE_BIT + ACCESS_TRANSFER_READ_BIT AccessFlags = C.VK_ACCESS_TRANSFER_READ_BIT + ACCESS_TRANSFER_WRITE_BIT AccessFlags = C.VK_ACCESS_TRANSFER_WRITE_BIT + ACCESS_SHADER_READ_BIT AccessFlags = C.VK_ACCESS_SHADER_READ_BIT + ACCESS_SHADER_WRITE_BIT AccessFlags = C.VK_ACCESS_SHADER_WRITE_BIT + ACCESS_COLOR_ATTACHMENT_READ_BIT AccessFlags = C.VK_ACCESS_COLOR_ATTACHMENT_READ_BIT + ACCESS_COLOR_ATTACHMENT_WRITE_BIT AccessFlags = C.VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT + ACCESS_HOST_READ_BIT AccessFlags = C.VK_ACCESS_HOST_READ_BIT + ACCESS_HOST_WRITE_BIT AccessFlags = C.VK_ACCESS_HOST_WRITE_BIT + ACCESS_VERTEX_ATTRIBUTE_READ_BIT AccessFlags = C.VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT + ACCESS_INDEX_READ_BIT AccessFlags = C.VK_ACCESS_INDEX_READ_BIT + + PIPELINE_BIND_POINT_COMPUTE PipelineBindPoint = C.VK_PIPELINE_BIND_POINT_COMPUTE + PIPELINE_BIND_POINT_GRAPHICS PipelineBindPoint = C.VK_PIPELINE_BIND_POINT_GRAPHICS + + INDEX_TYPE_UINT16 IndexType = C.VK_INDEX_TYPE_UINT16 + INDEX_TYPE_UINT32 IndexType = C.VK_INDEX_TYPE_UINT32 + + QUEUE_GRAPHICS_BIT QueueFlags = C.VK_QUEUE_GRAPHICS_BIT + QUEUE_COMPUTE_BIT QueueFlags = C.VK_QUEUE_COMPUTE_BIT +) + +var ( + once sync.Once + loadErr error + + loadFuncs []func(dlopen func(name string) *[0]byte) +) + +var funcs struct { + vkCreateInstance C.PFN_vkCreateInstance + vkDestroyInstance C.PFN_vkDestroyInstance + vkEnumeratePhysicalDevices C.PFN_vkEnumeratePhysicalDevices + vkGetPhysicalDeviceQueueFamilyProperties C.PFN_vkGetPhysicalDeviceQueueFamilyProperties + vkGetPhysicalDeviceFormatProperties C.PFN_vkGetPhysicalDeviceFormatProperties + vkCreateDevice C.PFN_vkCreateDevice + vkDestroyDevice C.PFN_vkDestroyDevice + vkGetDeviceQueue C.PFN_vkGetDeviceQueue + vkCreateImageView C.PFN_vkCreateImageView + vkDestroyImageView C.PFN_vkDestroyImageView + vkCreateFramebuffer C.PFN_vkCreateFramebuffer + vkDestroyFramebuffer C.PFN_vkDestroyFramebuffer + vkDeviceWaitIdle C.PFN_vkDeviceWaitIdle + vkQueueWaitIdle C.PFN_vkQueueWaitIdle + vkCreateSemaphore C.PFN_vkCreateSemaphore + vkDestroySemaphore C.PFN_vkDestroySemaphore + vkCreateRenderPass C.PFN_vkCreateRenderPass + vkDestroyRenderPass C.PFN_vkDestroyRenderPass + vkCreateCommandPool C.PFN_vkCreateCommandPool + vkDestroyCommandPool C.PFN_vkDestroyCommandPool + vkAllocateCommandBuffers C.PFN_vkAllocateCommandBuffers + vkFreeCommandBuffers C.PFN_vkFreeCommandBuffers + vkBeginCommandBuffer C.PFN_vkBeginCommandBuffer + vkEndCommandBuffer C.PFN_vkEndCommandBuffer + vkQueueSubmit C.PFN_vkQueueSubmit + vkCmdBeginRenderPass C.PFN_vkCmdBeginRenderPass + vkCmdEndRenderPass C.PFN_vkCmdEndRenderPass + vkCmdCopyBuffer C.PFN_vkCmdCopyBuffer + vkCmdCopyBufferToImage C.PFN_vkCmdCopyBufferToImage + vkCmdPipelineBarrier C.PFN_vkCmdPipelineBarrier + vkCmdPushConstants C.PFN_vkCmdPushConstants + vkCmdBindPipeline C.PFN_vkCmdBindPipeline + vkCmdBindVertexBuffers C.PFN_vkCmdBindVertexBuffers + vkCmdSetViewport C.PFN_vkCmdSetViewport + vkCmdBindIndexBuffer C.PFN_vkCmdBindIndexBuffer + vkCmdDraw C.PFN_vkCmdDraw + vkCmdDrawIndexed C.PFN_vkCmdDrawIndexed + vkCmdBindDescriptorSets C.PFN_vkCmdBindDescriptorSets + vkCmdCopyImageToBuffer C.PFN_vkCmdCopyImageToBuffer + vkCmdDispatch C.PFN_vkCmdDispatch + vkCreateImage C.PFN_vkCreateImage + vkDestroyImage C.PFN_vkDestroyImage + vkGetImageMemoryRequirements C.PFN_vkGetImageMemoryRequirements + vkAllocateMemory C.PFN_vkAllocateMemory + vkBindImageMemory C.PFN_vkBindImageMemory + vkFreeMemory C.PFN_vkFreeMemory + vkGetPhysicalDeviceMemoryProperties C.PFN_vkGetPhysicalDeviceMemoryProperties + vkCreateSampler C.PFN_vkCreateSampler + vkDestroySampler C.PFN_vkDestroySampler + vkCreateBuffer C.PFN_vkCreateBuffer + vkDestroyBuffer C.PFN_vkDestroyBuffer + vkGetBufferMemoryRequirements C.PFN_vkGetBufferMemoryRequirements + vkBindBufferMemory C.PFN_vkBindBufferMemory + vkCreateShaderModule C.PFN_vkCreateShaderModule + vkDestroyShaderModule C.PFN_vkDestroyShaderModule + vkCreateGraphicsPipelines C.PFN_vkCreateGraphicsPipelines + vkDestroyPipeline C.PFN_vkDestroyPipeline + vkCreatePipelineLayout C.PFN_vkCreatePipelineLayout + vkDestroyPipelineLayout C.PFN_vkDestroyPipelineLayout + vkCreateDescriptorSetLayout C.PFN_vkCreateDescriptorSetLayout + vkDestroyDescriptorSetLayout C.PFN_vkDestroyDescriptorSetLayout + vkMapMemory C.PFN_vkMapMemory + vkUnmapMemory C.PFN_vkUnmapMemory + vkResetCommandBuffer C.PFN_vkResetCommandBuffer + vkCreateDescriptorPool C.PFN_vkCreateDescriptorPool + vkDestroyDescriptorPool C.PFN_vkDestroyDescriptorPool + vkAllocateDescriptorSets C.PFN_vkAllocateDescriptorSets + vkFreeDescriptorSets C.PFN_vkFreeDescriptorSets + vkUpdateDescriptorSets C.PFN_vkUpdateDescriptorSets + vkResetDescriptorPool C.PFN_vkResetDescriptorPool + vkCmdCopyImage C.PFN_vkCmdCopyImage + vkCreateComputePipelines C.PFN_vkCreateComputePipelines + vkCreateFence C.PFN_vkCreateFence + vkDestroyFence C.PFN_vkDestroyFence + vkWaitForFences C.PFN_vkWaitForFences + vkResetFences C.PFN_vkResetFences + vkGetPhysicalDeviceProperties C.PFN_vkGetPhysicalDeviceProperties + + vkGetPhysicalDeviceSurfaceSupportKHR C.PFN_vkGetPhysicalDeviceSurfaceSupportKHR + vkDestroySurfaceKHR C.PFN_vkDestroySurfaceKHR + vkGetPhysicalDeviceSurfaceFormatsKHR C.PFN_vkGetPhysicalDeviceSurfaceFormatsKHR + vkGetPhysicalDeviceSurfacePresentModesKHR C.PFN_vkGetPhysicalDeviceSurfacePresentModesKHR + vkGetPhysicalDeviceSurfaceCapabilitiesKHR C.PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR + + vkCreateSwapchainKHR C.PFN_vkCreateSwapchainKHR + vkDestroySwapchainKHR C.PFN_vkDestroySwapchainKHR + vkGetSwapchainImagesKHR C.PFN_vkGetSwapchainImagesKHR + vkAcquireNextImageKHR C.PFN_vkAcquireNextImageKHR + vkQueuePresentKHR C.PFN_vkQueuePresentKHR +} + +var ( + nilSurface C.VkSurfaceKHR + nilSwapchain C.VkSwapchainKHR + nilSemaphore C.VkSemaphore + nilImageView C.VkImageView + nilRenderPass C.VkRenderPass + nilFramebuffer C.VkFramebuffer + nilCommandPool C.VkCommandPool + nilImage C.VkImage + nilDeviceMemory C.VkDeviceMemory + nilSampler C.VkSampler + nilBuffer C.VkBuffer + nilShaderModule C.VkShaderModule + nilPipeline C.VkPipeline + nilPipelineCache C.VkPipelineCache + nilPipelineLayout C.VkPipelineLayout + nilDescriptorSetLayout C.VkDescriptorSetLayout + nilDescriptorPool C.VkDescriptorPool + nilDescriptorSet C.VkDescriptorSet + nilFence C.VkFence +) + +func vkInit() error { + once.Do(func() { + var libName string + switch { + case runtime.GOOS == "android": + libName = "libvulkan.so" + default: + libName = "libvulkan.so.1" + } + lib := dlopen(libName) + if lib == nil { + loadErr = fmt.Errorf("vulkan: %s", C.GoString(C.dlerror())) + return + } + dlopen := func(name string) *[0]byte { + return (*[0]byte)(dlsym(lib, name)) + } + must := func(name string) *[0]byte { + ptr := dlopen(name) + if ptr != nil { + return ptr + } + if loadErr == nil { + loadErr = fmt.Errorf("vulkan: function %q not found: %s", name, C.GoString(C.dlerror())) + } + return nil + } + funcs.vkCreateInstance = must("vkCreateInstance") + funcs.vkDestroyInstance = must("vkDestroyInstance") + funcs.vkEnumeratePhysicalDevices = must("vkEnumeratePhysicalDevices") + funcs.vkGetPhysicalDeviceQueueFamilyProperties = must("vkGetPhysicalDeviceQueueFamilyProperties") + funcs.vkGetPhysicalDeviceFormatProperties = must("vkGetPhysicalDeviceFormatProperties") + funcs.vkCreateDevice = must("vkCreateDevice") + funcs.vkDestroyDevice = must("vkDestroyDevice") + funcs.vkGetDeviceQueue = must("vkGetDeviceQueue") + funcs.vkCreateImageView = must("vkCreateImageView") + funcs.vkDestroyImageView = must("vkDestroyImageView") + funcs.vkCreateFramebuffer = must("vkCreateFramebuffer") + funcs.vkDestroyFramebuffer = must("vkDestroyFramebuffer") + funcs.vkDeviceWaitIdle = must("vkDeviceWaitIdle") + funcs.vkQueueWaitIdle = must("vkQueueWaitIdle") + funcs.vkCreateSemaphore = must("vkCreateSemaphore") + funcs.vkDestroySemaphore = must("vkDestroySemaphore") + funcs.vkCreateRenderPass = must("vkCreateRenderPass") + funcs.vkDestroyRenderPass = must("vkDestroyRenderPass") + funcs.vkCreateCommandPool = must("vkCreateCommandPool") + funcs.vkDestroyCommandPool = must("vkDestroyCommandPool") + funcs.vkAllocateCommandBuffers = must("vkAllocateCommandBuffers") + funcs.vkFreeCommandBuffers = must("vkFreeCommandBuffers") + funcs.vkBeginCommandBuffer = must("vkBeginCommandBuffer") + funcs.vkEndCommandBuffer = must("vkEndCommandBuffer") + funcs.vkQueueSubmit = must("vkQueueSubmit") + funcs.vkCmdBeginRenderPass = must("vkCmdBeginRenderPass") + funcs.vkCmdEndRenderPass = must("vkCmdEndRenderPass") + funcs.vkCmdCopyBuffer = must("vkCmdCopyBuffer") + funcs.vkCmdCopyBufferToImage = must("vkCmdCopyBufferToImage") + funcs.vkCmdPipelineBarrier = must("vkCmdPipelineBarrier") + funcs.vkCmdPushConstants = must("vkCmdPushConstants") + funcs.vkCmdBindPipeline = must("vkCmdBindPipeline") + funcs.vkCmdBindVertexBuffers = must("vkCmdBindVertexBuffers") + funcs.vkCmdSetViewport = must("vkCmdSetViewport") + funcs.vkCmdBindIndexBuffer = must("vkCmdBindIndexBuffer") + funcs.vkCmdDraw = must("vkCmdDraw") + funcs.vkCmdDrawIndexed = must("vkCmdDrawIndexed") + funcs.vkCmdBindDescriptorSets = must("vkCmdBindDescriptorSets") + funcs.vkCmdCopyImageToBuffer = must("vkCmdCopyImageToBuffer") + funcs.vkCmdDispatch = must("vkCmdDispatch") + funcs.vkCreateImage = must("vkCreateImage") + funcs.vkDestroyImage = must("vkDestroyImage") + funcs.vkGetImageMemoryRequirements = must("vkGetImageMemoryRequirements") + funcs.vkAllocateMemory = must("vkAllocateMemory") + funcs.vkBindImageMemory = must("vkBindImageMemory") + funcs.vkFreeMemory = must("vkFreeMemory") + funcs.vkGetPhysicalDeviceMemoryProperties = must("vkGetPhysicalDeviceMemoryProperties") + funcs.vkCreateSampler = must("vkCreateSampler") + funcs.vkDestroySampler = must("vkDestroySampler") + funcs.vkCreateBuffer = must("vkCreateBuffer") + funcs.vkDestroyBuffer = must("vkDestroyBuffer") + funcs.vkGetBufferMemoryRequirements = must("vkGetBufferMemoryRequirements") + funcs.vkBindBufferMemory = must("vkBindBufferMemory") + funcs.vkCreateShaderModule = must("vkCreateShaderModule") + funcs.vkDestroyShaderModule = must("vkDestroyShaderModule") + funcs.vkCreateGraphicsPipelines = must("vkCreateGraphicsPipelines") + funcs.vkDestroyPipeline = must("vkDestroyPipeline") + funcs.vkCreatePipelineLayout = must("vkCreatePipelineLayout") + funcs.vkDestroyPipelineLayout = must("vkDestroyPipelineLayout") + funcs.vkCreateDescriptorSetLayout = must("vkCreateDescriptorSetLayout") + funcs.vkDestroyDescriptorSetLayout = must("vkDestroyDescriptorSetLayout") + funcs.vkMapMemory = must("vkMapMemory") + funcs.vkUnmapMemory = must("vkUnmapMemory") + funcs.vkResetCommandBuffer = must("vkResetCommandBuffer") + funcs.vkCreateDescriptorPool = must("vkCreateDescriptorPool") + funcs.vkDestroyDescriptorPool = must("vkDestroyDescriptorPool") + funcs.vkAllocateDescriptorSets = must("vkAllocateDescriptorSets") + funcs.vkFreeDescriptorSets = must("vkFreeDescriptorSets") + funcs.vkUpdateDescriptorSets = must("vkUpdateDescriptorSets") + funcs.vkResetDescriptorPool = must("vkResetDescriptorPool") + funcs.vkCmdCopyImage = must("vkCmdCopyImage") + funcs.vkCreateComputePipelines = must("vkCreateComputePipelines") + funcs.vkCreateFence = must("vkCreateFence") + funcs.vkDestroyFence = must("vkDestroyFence") + funcs.vkWaitForFences = must("vkWaitForFences") + funcs.vkResetFences = must("vkResetFences") + funcs.vkGetPhysicalDeviceProperties = must("vkGetPhysicalDeviceProperties") + + funcs.vkGetPhysicalDeviceSurfaceSupportKHR = dlopen("vkGetPhysicalDeviceSurfaceSupportKHR") + funcs.vkDestroySurfaceKHR = dlopen("vkDestroySurfaceKHR") + funcs.vkGetPhysicalDeviceSurfaceFormatsKHR = dlopen("vkGetPhysicalDeviceSurfaceFormatsKHR") + funcs.vkGetPhysicalDeviceSurfacePresentModesKHR = dlopen("vkGetPhysicalDeviceSurfacePresentModesKHR") + funcs.vkGetPhysicalDeviceSurfaceCapabilitiesKHR = dlopen("vkGetPhysicalDeviceSurfaceCapabilitiesKHR") + + funcs.vkCreateSwapchainKHR = dlopen("vkCreateSwapchainKHR") + funcs.vkDestroySwapchainKHR = dlopen("vkDestroySwapchainKHR") + funcs.vkGetSwapchainImagesKHR = dlopen("vkGetSwapchainImagesKHR") + funcs.vkAcquireNextImageKHR = dlopen("vkAcquireNextImageKHR") + funcs.vkQueuePresentKHR = dlopen("vkQueuePresentKHR") + + for _, f := range loadFuncs { + f(dlopen) + } + }) + return loadErr +} + +func CreateInstance(exts ...string) (Instance, error) { + if err := vkInit(); err != nil { + return nil, err + } + inf := C.VkInstanceCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + } + if len(exts) > 0 { + cexts := mallocCStringArr(exts) + defer freeCStringArr(cexts) + inf.enabledExtensionCount = C.uint32_t(len(exts)) + inf.ppEnabledExtensionNames = &cexts[0] + } + var inst Instance + if err := vkErr(C.vkCreateInstance(funcs.vkCreateInstance, inf, nil, &inst)); err != nil { + return nil, fmt.Errorf("vulkan: vkCreateInstance: %w", err) + } + return inst, nil +} + +func mallocCStringArr(s []string) []*C.char { + carr := make([]*C.char, len(s)) + for i, ext := range s { + carr[i] = C.CString(ext) + } + return carr +} + +func freeCStringArr(s []*C.char) { + for i := range s { + C.free(unsafe.Pointer(s[i])) + s[i] = nil + } +} + +func DestroyInstance(inst Instance) { + C.vkDestroyInstance(funcs.vkDestroyInstance, inst, nil) +} + +func GetPhysicalDeviceQueueFamilyProperties(pd PhysicalDevice) []QueueFamilyProperties { + var count C.uint32_t + C.vkGetPhysicalDeviceQueueFamilyProperties(funcs.vkGetPhysicalDeviceQueueFamilyProperties, pd, &count, nil) + if count == 0 { + return nil + } + queues := make([]C.VkQueueFamilyProperties, count) + C.vkGetPhysicalDeviceQueueFamilyProperties(funcs.vkGetPhysicalDeviceQueueFamilyProperties, pd, &count, &queues[0]) + return queues +} + +func EnumeratePhysicalDevices(inst Instance) ([]PhysicalDevice, error) { + var count C.uint32_t + if err := vkErr(C.vkEnumeratePhysicalDevices(funcs.vkEnumeratePhysicalDevices, inst, &count, nil)); err != nil { + return nil, fmt.Errorf("vulkan: vkEnumeratePhysicalDevices: %w", err) + } + if count == 0 { + return nil, nil + } + devs := make([]C.VkPhysicalDevice, count) + if err := vkErr(C.vkEnumeratePhysicalDevices(funcs.vkEnumeratePhysicalDevices, inst, &count, &devs[0])); err != nil { + return nil, fmt.Errorf("vulkan: vkEnumeratePhysicalDevices: %w", err) + } + return devs, nil +} + +func ChoosePhysicalDevice(inst Instance, surf Surface) (PhysicalDevice, int, error) { + devs, err := EnumeratePhysicalDevices(inst) + if err != nil { + return nil, 0, err + } + for _, pd := range devs { + var props C.VkPhysicalDeviceProperties + C.vkGetPhysicalDeviceProperties(funcs.vkGetPhysicalDeviceProperties, pd, &props) + // The lavapipe software implementation doesn't work well rendering to a surface. + // See https://gitlab.freedesktop.org/mesa/mesa/-/issues/5473. + if surf != 0 && props.deviceType == C.VK_PHYSICAL_DEVICE_TYPE_CPU { + continue + } + const caps = C.VK_QUEUE_GRAPHICS_BIT | C.VK_QUEUE_COMPUTE_BIT + queueIdx, ok, err := chooseQueue(pd, surf, caps) + if err != nil { + return nil, 0, err + } + if !ok { + continue + } + if surf != nilSurface { + _, fmtFound, err := chooseFormat(pd, surf) + if err != nil { + return nil, 0, err + } + _, modFound, err := choosePresentMode(pd, surf) + if err != nil { + return nil, 0, err + } + if !fmtFound || !modFound { + continue + } + } + return pd, queueIdx, nil + } + return nil, 0, errors.New("vulkan: no suitable device found") +} + +func CreateDeviceAndQueue(pd C.VkPhysicalDevice, queueIdx int, exts ...string) (Device, error) { + priority := C.float(1.0) + qinf := C.VkDeviceQueueCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + queueCount: 1, + queueFamilyIndex: C.uint32_t(queueIdx), + pQueuePriorities: &priority, + } + inf := C.VkDeviceCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + queueCreateInfoCount: 1, + enabledExtensionCount: C.uint32_t(len(exts)), + } + if len(exts) > 0 { + cexts := mallocCStringArr(exts) + defer freeCStringArr(cexts) + inf.ppEnabledExtensionNames = &cexts[0] + } + var dev Device + if err := vkErr(C.vkCreateDevice(funcs.vkCreateDevice, pd, inf, qinf, nil, &dev)); err != nil { + return nil, fmt.Errorf("vulkan: vkCreateDevice: %w", err) + } + return dev, nil +} + +func GetDeviceQueue(d Device, queueFamily, queueIndex int) Queue { + var queue Queue + C.vkGetDeviceQueue(funcs.vkGetDeviceQueue, d, C.uint32_t(queueFamily), C.uint32_t(queueIndex), &queue) + return queue +} + +func GetPhysicalDeviceSurfaceCapabilities(pd PhysicalDevice, surf Surface) (SurfaceCapabilities, error) { + var caps C.VkSurfaceCapabilitiesKHR + err := vkErr(C.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(funcs.vkGetPhysicalDeviceSurfaceCapabilitiesKHR, pd, surf, &caps)) + if err != nil { + return SurfaceCapabilities{}, fmt.Errorf("vulkan: vkGetPhysicalDeviceSurfaceCapabilitiesKHR: %w", err) + } + return caps, nil +} + +func CreateSwapchain(pd PhysicalDevice, d Device, surf Surface, width, height int, old Swapchain) (Swapchain, []Image, Format, error) { + caps, err := GetPhysicalDeviceSurfaceCapabilities(pd, surf) + if err != nil { + return nilSwapchain, nil, 0, err + } + mode, modeOK, err := choosePresentMode(pd, surf) + if err != nil { + return nilSwapchain, nil, 0, err + } + format, fmtOK, err := chooseFormat(pd, surf) + if err != nil { + return nilSwapchain, nil, 0, err + } + if !modeOK || !fmtOK { + // This shouldn't happen because CreateDeviceAndQueue found at least + // one valid format and present mode. + return nilSwapchain, nil, 0, errors.New("vulkan: no valid format and present mode found") + } + // Find supported alpha composite mode. It doesn't matter which one, because rendering is + // always opaque. + alphaComp := C.VkCompositeAlphaFlagBitsKHR(1) + for caps.supportedCompositeAlpha&C.VkCompositeAlphaFlagsKHR(alphaComp) == 0 { + alphaComp <<= 1 + } + trans := C.VkSurfaceTransformFlagBitsKHR(C.VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) + if caps.supportedTransforms&C.VkSurfaceTransformFlagsKHR(trans) == 0 { + return nilSwapchain, nil, 0, errors.New("vulkan: VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR not supported") + } + inf := C.VkSwapchainCreateInfoKHR{ + sType: C.VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + surface: surf, + minImageCount: caps.minImageCount, + imageFormat: format.format, + imageColorSpace: format.colorSpace, + imageExtent: C.VkExtent2D{width: C.uint32_t(width), height: C.uint32_t(height)}, + imageArrayLayers: 1, + imageUsage: C.VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + imageSharingMode: C.VK_SHARING_MODE_EXCLUSIVE, + preTransform: trans, + presentMode: mode, + compositeAlpha: C.VkCompositeAlphaFlagBitsKHR(alphaComp), + clipped: C.VK_TRUE, + oldSwapchain: old, + } + var swchain Swapchain + if err := vkErr(C.vkCreateSwapchainKHR(funcs.vkCreateSwapchainKHR, d, &inf, nil, &swchain)); err != nil { + return nilSwapchain, nil, 0, fmt.Errorf("vulkan: vkCreateSwapchainKHR: %w", err) + } + var count C.uint32_t + if err := vkErr(C.vkGetSwapchainImagesKHR(funcs.vkGetSwapchainImagesKHR, d, swchain, &count, nil)); err != nil { + DestroySwapchain(d, swchain) + return nilSwapchain, nil, 0, fmt.Errorf("vulkan: vkGetSwapchainImagesKHR: %w", err) + } + if count == 0 { + DestroySwapchain(d, swchain) + return nilSwapchain, nil, 0, errors.New("vulkan: vkGetSwapchainImagesKHR returned no images") + } + imgs := make([]Image, count) + if err := vkErr(C.vkGetSwapchainImagesKHR(funcs.vkGetSwapchainImagesKHR, d, swchain, &count, &imgs[0])); err != nil { + DestroySwapchain(d, swchain) + return nilSwapchain, nil, 0, fmt.Errorf("vulkan: vkGetSwapchainImagesKHR: %w", err) + } + return swchain, imgs, format.format, nil +} + +func DestroySwapchain(d Device, swchain Swapchain) { + C.vkDestroySwapchainKHR(funcs.vkDestroySwapchainKHR, d, swchain, nil) +} + +func AcquireNextImage(d Device, swchain Swapchain, sem Semaphore, fence Fence) (int, error) { + res := C.vkAcquireNextImageKHR(funcs.vkAcquireNextImageKHR, d, swchain, math.MaxUint64, sem, fence) + if err := vkErr(res.res); err != nil { + return 0, fmt.Errorf("vulkan: vkAcquireNextImageKHR: %w", err) + } + return int(res.uint), nil +} + +func PresentQueue(q Queue, swchain Swapchain, sem Semaphore, imgIdx int) error { + cidx := C.uint32_t(imgIdx) + inf := C.VkPresentInfoKHR{ + sType: C.VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + swapchainCount: 1, + pSwapchains: &swchain, + pImageIndices: &cidx, + } + if sem != nilSemaphore { + inf.waitSemaphoreCount = 1 + inf.pWaitSemaphores = &sem + } + if err := vkErr(C.vkQueuePresentKHR(funcs.vkQueuePresentKHR, q, inf)); err != nil { + return fmt.Errorf("vulkan: vkQueuePresentKHR: %w", err) + } + return nil +} + +func CreateImageView(d Device, img Image, format Format) (ImageView, error) { + inf := C.VkImageViewCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + image: img, + viewType: C.VK_IMAGE_VIEW_TYPE_2D, + format: format, + subresourceRange: C.VkImageSubresourceRange{ + aspectMask: C.VK_IMAGE_ASPECT_COLOR_BIT, + levelCount: C.VK_REMAINING_MIP_LEVELS, + layerCount: C.VK_REMAINING_ARRAY_LAYERS, + }, + } + var view C.VkImageView + if err := vkErr(C.vkCreateImageView(funcs.vkCreateImageView, d, &inf, nil, &view)); err != nil { + return nilImageView, fmt.Errorf("vulkan: vkCreateImageView: %w", err) + } + return view, nil +} + +func DestroyImageView(d Device, view ImageView) { + C.vkDestroyImageView(funcs.vkDestroyImageView, d, view, nil) +} + +func CreateRenderPass(d Device, format Format, loadOp AttachmentLoadOp, initialLayout, finalLayout ImageLayout, passDeps []SubpassDependency) (RenderPass, error) { + att := C.VkAttachmentDescription{ + format: format, + samples: C.VK_SAMPLE_COUNT_1_BIT, + loadOp: loadOp, + storeOp: C.VK_ATTACHMENT_STORE_OP_STORE, + stencilLoadOp: C.VK_ATTACHMENT_LOAD_OP_DONT_CARE, + stencilStoreOp: C.VK_ATTACHMENT_STORE_OP_DONT_CARE, + initialLayout: initialLayout, + finalLayout: finalLayout, + } + + ref := C.VkAttachmentReference{ + attachment: 0, + layout: C.VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + } + + sub := C.VkSubpassDescription{ + pipelineBindPoint: C.VK_PIPELINE_BIND_POINT_GRAPHICS, + colorAttachmentCount: 1, + pColorAttachments: &ref, + } + + inf := C.VkRenderPassCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + attachmentCount: 1, + pAttachments: &att, + subpassCount: 1, + } + if n := len(passDeps); n > 0 { + inf.dependencyCount = C.uint32_t(n) + inf.pDependencies = &passDeps[0] + } + + var pass RenderPass + if err := vkErr(C.vkCreateRenderPass(funcs.vkCreateRenderPass, d, inf, sub, nil, &pass)); err != nil { + return nilRenderPass, fmt.Errorf("vulkan: vkCreateRenderPass: %w", err) + } + return pass, nil +} + +func DestroyRenderPass(d Device, r RenderPass) { + C.vkDestroyRenderPass(funcs.vkDestroyRenderPass, d, r, nil) +} + +func CreateFramebuffer(d Device, rp RenderPass, view ImageView, width, height int) (Framebuffer, error) { + inf := C.VkFramebufferCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + renderPass: rp, + attachmentCount: 1, + pAttachments: &view, + width: C.uint32_t(width), + height: C.uint32_t(height), + layers: 1, + } + var fbo Framebuffer + if err := vkErr(C.vkCreateFramebuffer(funcs.vkCreateFramebuffer, d, inf, nil, &fbo)); err != nil { + return nilFramebuffer, fmt.Errorf("vulkan: vkCreateFramebuffer: %w", err) + } + return fbo, nil + +} + +func DestroyFramebuffer(d Device, f Framebuffer) { + C.vkDestroyFramebuffer(funcs.vkDestroyFramebuffer, d, f, nil) +} + +func DeviceWaitIdle(d Device) error { + if err := vkErr(C.vkDeviceWaitIdle(funcs.vkDeviceWaitIdle, d)); err != nil { + return fmt.Errorf("vulkan: vkDeviceWaitIdle: %w", err) + } + return nil +} + +func QueueWaitIdle(q Queue) error { + if err := vkErr(C.vkQueueWaitIdle(funcs.vkQueueWaitIdle, q)); err != nil { + return fmt.Errorf("vulkan: vkQueueWaitIdle: %w", err) + } + return nil +} + +func CreateSemaphore(d Device) (Semaphore, error) { + inf := C.VkSemaphoreCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + } + var sem Semaphore + err := vkErr(C.vkCreateSemaphore(funcs.vkCreateSemaphore, d, &inf, nil, &sem)) + if err != nil { + return nilSemaphore, fmt.Errorf("vulkan: vkCreateSemaphore: %w", err) + } + return sem, err +} + +func DestroySemaphore(d Device, sem Semaphore) { + C.vkDestroySemaphore(funcs.vkDestroySemaphore, d, sem, nil) +} + +func DestroyDevice(dev Device) { + C.vkDestroyDevice(funcs.vkDestroyDevice, dev, nil) +} + +func DestroySurface(inst Instance, s Surface) { + C.vkDestroySurfaceKHR(funcs.vkDestroySurfaceKHR, inst, s, nil) +} + +func CreateCommandPool(d Device, queueIndex int) (CommandPool, error) { + inf := C.VkCommandPoolCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + queueFamilyIndex: C.uint32_t(queueIndex), + flags: C.VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | C.VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + } + + var pool CommandPool + if err := vkErr(C.vkCreateCommandPool(funcs.vkCreateCommandPool, d, &inf, nil, &pool)); err != nil { + return nilCommandPool, fmt.Errorf("vulkan: vkCreateCommandPool: %w", err) + } + return pool, nil +} + +func DestroyCommandPool(d Device, pool CommandPool) { + C.vkDestroyCommandPool(funcs.vkDestroyCommandPool, d, pool, nil) +} + +func AllocateCommandBuffer(d Device, pool CommandPool) (CommandBuffer, error) { + inf := C.VkCommandBufferAllocateInfo{ + sType: C.VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + commandPool: pool, + level: C.VK_COMMAND_BUFFER_LEVEL_PRIMARY, + commandBufferCount: 1, + } + + var buf CommandBuffer + if err := vkErr(C.vkAllocateCommandBuffers(funcs.vkAllocateCommandBuffers, d, &inf, &buf)); err != nil { + return nil, fmt.Errorf("vulkan: vkAllocateCommandBuffers: %w", err) + } + return buf, nil +} + +func FreeCommandBuffers(d Device, pool CommandPool, bufs ...CommandBuffer) { + if len(bufs) == 0 { + return + } + C.vkFreeCommandBuffers(funcs.vkFreeCommandBuffers, d, pool, C.uint32_t(len(bufs)), &bufs[0]) +} + +func BeginCommandBuffer(buf CommandBuffer) error { + inf := C.VkCommandBufferBeginInfo{ + sType: C.VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + flags: C.VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + } + if err := vkErr(C.vkBeginCommandBuffer(funcs.vkBeginCommandBuffer, buf, inf)); err != nil { + return fmt.Errorf("vulkan: vkBeginCommandBuffer: %w", err) + } + return nil +} + +func EndCommandBuffer(buf CommandBuffer) error { + if err := vkErr(C.vkEndCommandBuffer(funcs.vkEndCommandBuffer, buf)); err != nil { + return fmt.Errorf("vulkan: vkEndCommandBuffer: %w", err) + } + return nil +} + +func QueueSubmit(q Queue, buf CommandBuffer, waitSems []Semaphore, waitStages []PipelineStageFlags, sigSems []Semaphore, fence Fence) error { + inf := C.VkSubmitInfo{ + sType: C.VK_STRUCTURE_TYPE_SUBMIT_INFO, + commandBufferCount: 1, + pCommandBuffers: &buf, + } + if len(waitSems) > 0 { + if len(waitSems) != len(waitStages) { + panic("len(waitSems) != len(waitStages)") + } + inf.waitSemaphoreCount = C.uint32_t(len(waitSems)) + inf.pWaitSemaphores = &waitSems[0] + inf.pWaitDstStageMask = &waitStages[0] + } + if len(sigSems) > 0 { + inf.signalSemaphoreCount = C.uint32_t(len(sigSems)) + inf.pSignalSemaphores = &sigSems[0] + } + if err := vkErr(C.vkQueueSubmit(funcs.vkQueueSubmit, q, inf, fence)); err != nil { + return fmt.Errorf("vulkan: vkQueueSubmit: %w", err) + } + return nil +} + +func CmdBeginRenderPass(buf CommandBuffer, rp RenderPass, fbo Framebuffer, width, height int, clearCol [4]float32) { + cclearCol := [4]C.float{C.float(clearCol[0]), C.float(clearCol[1]), C.float(clearCol[2]), C.float(clearCol[3])} + inf := C.VkRenderPassBeginInfo{ + sType: C.VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + renderPass: rp, + framebuffer: fbo, + renderArea: C.VkRect2D{extent: C.VkExtent2D{width: C.uint32_t(width), height: C.uint32_t(height)}}, + clearValueCount: 1, + pClearValues: (*C.VkClearValue)(unsafe.Pointer(&cclearCol)), + } + C.vkCmdBeginRenderPass(funcs.vkCmdBeginRenderPass, buf, inf, C.VK_SUBPASS_CONTENTS_INLINE) +} + +func CmdEndRenderPass(buf CommandBuffer) { + C.vkCmdEndRenderPass(funcs.vkCmdEndRenderPass, buf) +} + +func CmdCopyBuffer(cmdBuf CommandBuffer, src, dst Buffer, srcOff, dstOff, size int) { + C.vkCmdCopyBuffer(funcs.vkCmdCopyBuffer, cmdBuf, src, dst, 1, &C.VkBufferCopy{ + srcOffset: C.VkDeviceSize(srcOff), + dstOffset: C.VkDeviceSize(dstOff), + size: C.VkDeviceSize(size), + }) +} + +func CmdCopyBufferToImage(cmdBuf CommandBuffer, src Buffer, dst Image, layout ImageLayout, copy BufferImageCopy) { + C.vkCmdCopyBufferToImage(funcs.vkCmdCopyBufferToImage, cmdBuf, src, dst, layout, 1, ©) +} + +func CmdPipelineBarrier(cmdBuf CommandBuffer, srcStage, dstStage PipelineStageFlags, flags DependencyFlags, memBarriers []MemoryBarrier, bufBarriers []BufferMemoryBarrier, imgBarriers []ImageMemoryBarrier) { + var memPtr *MemoryBarrier + if len(memBarriers) > 0 { + memPtr = &memBarriers[0] + } + var bufPtr *BufferMemoryBarrier + if len(bufBarriers) > 0 { + bufPtr = &bufBarriers[0] + } + var imgPtr *ImageMemoryBarrier + if len(imgBarriers) > 0 { + imgPtr = &imgBarriers[0] + } + C.vkCmdPipelineBarrier(funcs.vkCmdPipelineBarrier, cmdBuf, srcStage, dstStage, flags, + C.uint32_t(len(memBarriers)), memPtr, + C.uint32_t(len(bufBarriers)), bufPtr, + C.uint32_t(len(imgBarriers)), imgPtr) +} + +func CmdPushConstants(cmdBuf CommandBuffer, layout PipelineLayout, stages ShaderStageFlags, offset int, data []byte) { + if len(data) == 0 { + return + } + C.vkCmdPushConstants(funcs.vkCmdPushConstants, cmdBuf, layout, stages, C.uint32_t(offset), C.uint32_t(len(data)), unsafe.Pointer(&data[0])) +} + +func CmdBindPipeline(cmdBuf CommandBuffer, bindPoint PipelineBindPoint, pipe Pipeline) { + C.vkCmdBindPipeline(funcs.vkCmdBindPipeline, cmdBuf, bindPoint, pipe) +} + +func CmdBindVertexBuffers(cmdBuf CommandBuffer, first int, buffers []Buffer, sizes []DeviceSize) { + if len(buffers) == 0 { + return + } + C.vkCmdBindVertexBuffers(funcs.vkCmdBindVertexBuffers, cmdBuf, C.uint32_t(first), C.uint32_t(len(buffers)), &buffers[0], &sizes[0]) +} + +func CmdSetViewport(cmdBuf CommandBuffer, first int, viewports ...Viewport) { + if len(viewports) == 0 { + return + } + C.vkCmdSetViewport(funcs.vkCmdSetViewport, cmdBuf, C.uint32_t(first), C.uint32_t(len(viewports)), &viewports[0]) +} + +func CmdBindIndexBuffer(cmdBuf CommandBuffer, buffer Buffer, offset int, typ IndexType) { + C.vkCmdBindIndexBuffer(funcs.vkCmdBindIndexBuffer, cmdBuf, buffer, C.VkDeviceSize(offset), typ) +} + +func CmdDraw(cmdBuf CommandBuffer, vertCount, instCount, firstVert, firstInst int) { + C.vkCmdDraw(funcs.vkCmdDraw, cmdBuf, C.uint32_t(vertCount), C.uint32_t(instCount), C.uint32_t(firstVert), C.uint32_t(firstInst)) +} + +func CmdDrawIndexed(cmdBuf CommandBuffer, idxCount, instCount, firstIdx, vertOff, firstInst int) { + C.vkCmdDrawIndexed(funcs.vkCmdDrawIndexed, cmdBuf, C.uint32_t(idxCount), C.uint32_t(instCount), C.uint32_t(firstIdx), C.int32_t(vertOff), C.uint32_t(firstInst)) +} + +func GetPhysicalDeviceFormatProperties(physDev PhysicalDevice, format Format) FormatFeatureFlags { + var props C.VkFormatProperties + C.vkGetPhysicalDeviceFormatProperties(funcs.vkGetPhysicalDeviceFormatProperties, physDev, format, &props) + return FormatFeatureFlags(props.optimalTilingFeatures) +} + +func CmdBindDescriptorSets(cmdBuf CommandBuffer, point PipelineBindPoint, layout PipelineLayout, firstSet int, sets []DescriptorSet) { + C.vkCmdBindDescriptorSets(funcs.vkCmdBindDescriptorSets, cmdBuf, point, layout, C.uint32_t(firstSet), C.uint32_t(len(sets)), &sets[0], 0, nil) +} + +func CmdCopyImage(cmdBuf CommandBuffer, src Image, srcLayout ImageLayout, dst Image, dstLayout ImageLayout, regions []ImageCopy) { + if len(regions) == 0 { + return + } + C.vkCmdCopyImage(funcs.vkCmdCopyImage, cmdBuf, src, srcLayout, dst, dstLayout, C.uint32_t(len(regions)), ®ions[0]) +} + +func CmdCopyImageToBuffer(cmdBuf CommandBuffer, src Image, srcLayout ImageLayout, dst Buffer, regions []BufferImageCopy) { + if len(regions) == 0 { + return + } + C.vkCmdCopyImageToBuffer(funcs.vkCmdCopyImageToBuffer, cmdBuf, src, srcLayout, dst, C.uint32_t(len(regions)), ®ions[0]) +} + +func CmdDispatch(cmdBuf CommandBuffer, x, y, z int) { + C.vkCmdDispatch(funcs.vkCmdDispatch, cmdBuf, C.uint32_t(x), C.uint32_t(y), C.uint32_t(z)) +} + +func CreateImage(pd PhysicalDevice, d Device, format Format, width, height int, usage ImageUsageFlags) (Image, DeviceMemory, error) { + inf := C.VkImageCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + imageType: C.VK_IMAGE_TYPE_2D, + format: format, + extent: C.VkExtent3D{ + width: C.uint32_t(width), + height: C.uint32_t(height), + depth: 1, + }, + mipLevels: 1, + arrayLayers: 1, + samples: C.VK_SAMPLE_COUNT_1_BIT, + tiling: C.VK_IMAGE_TILING_OPTIMAL, + usage: usage, + initialLayout: C.VK_IMAGE_LAYOUT_UNDEFINED, + } + var img C.VkImage + if err := vkErr(C.vkCreateImage(funcs.vkCreateImage, d, &inf, nil, &img)); err != nil { + return nilImage, nilDeviceMemory, fmt.Errorf("vulkan: vkCreateImage: %w", err) + } + var memReqs C.VkMemoryRequirements + C.vkGetImageMemoryRequirements(funcs.vkGetImageMemoryRequirements, d, img, &memReqs) + + memIdx, found := findMemoryTypeIndex(pd, memReqs.memoryTypeBits, C.VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + if !found { + DestroyImage(d, img) + return nilImage, nilDeviceMemory, errors.New("vulkan: no memory type suitable for images found") + } + + memInf := C.VkMemoryAllocateInfo{ + sType: C.VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + allocationSize: memReqs.size, + memoryTypeIndex: C.uint32_t(memIdx), + } + var imgMem C.VkDeviceMemory + if err := vkErr(C.vkAllocateMemory(funcs.vkAllocateMemory, d, &memInf, nil, &imgMem)); err != nil { + DestroyImage(d, img) + return nilImage, nilDeviceMemory, fmt.Errorf("vulkan: vkAllocateMemory: %w", err) + } + + if err := vkErr(C.vkBindImageMemory(funcs.vkBindImageMemory, d, img, imgMem, 0)); err != nil { + FreeMemory(d, imgMem) + DestroyImage(d, img) + return nilImage, nilDeviceMemory, fmt.Errorf("vulkan: vkBindImageMemory: %w", err) + } + return img, imgMem, nil +} + +func DestroyImage(d Device, img Image) { + C.vkDestroyImage(funcs.vkDestroyImage, d, img, nil) +} + +func FreeMemory(d Device, mem DeviceMemory) { + C.vkFreeMemory(funcs.vkFreeMemory, d, mem, nil) +} + +func CreateSampler(d Device, minFilter, magFilter Filter) (Sampler, error) { + inf := C.VkSamplerCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + minFilter: minFilter, + magFilter: magFilter, + addressModeU: C.VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + addressModeV: C.VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + } + var s C.VkSampler + if err := vkErr(C.vkCreateSampler(funcs.vkCreateSampler, d, &inf, nil, &s)); err != nil { + return nilSampler, fmt.Errorf("vulkan: vkCreateSampler: %w", err) + } + return s, nil +} + +func DestroySampler(d Device, sampler Sampler) { + C.vkDestroySampler(funcs.vkDestroySampler, d, sampler, nil) +} + +func CreateBuffer(pd PhysicalDevice, d Device, size int, usage BufferUsageFlags, props MemoryPropertyFlags) (Buffer, DeviceMemory, error) { + inf := C.VkBufferCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + size: C.VkDeviceSize(size), + usage: usage, + } + var buf C.VkBuffer + if err := vkErr(C.vkCreateBuffer(funcs.vkCreateBuffer, d, &inf, nil, &buf)); err != nil { + return nilBuffer, nilDeviceMemory, fmt.Errorf("vulkan: vkCreateBuffer: %w", err) + } + + var memReqs C.VkMemoryRequirements + C.vkGetBufferMemoryRequirements(funcs.vkGetBufferMemoryRequirements, d, buf, &memReqs) + + memIdx, found := findMemoryTypeIndex(pd, memReqs.memoryTypeBits, props) + if !found { + DestroyBuffer(d, buf) + return nilBuffer, nilDeviceMemory, errors.New("vulkan: no memory suitable for buffers found") + } + memInf := C.VkMemoryAllocateInfo{ + sType: C.VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + allocationSize: memReqs.size, + memoryTypeIndex: C.uint32_t(memIdx), + } + + var mem C.VkDeviceMemory + if err := vkErr(C.vkAllocateMemory(funcs.vkAllocateMemory, d, &memInf, nil, &mem)); err != nil { + DestroyBuffer(d, buf) + return nilBuffer, nilDeviceMemory, fmt.Errorf("vulkan: vkAllocateMemory: %w", err) + } + + if err := vkErr(C.vkBindBufferMemory(funcs.vkBindBufferMemory, d, buf, mem, 0)); err != nil { + FreeMemory(d, mem) + DestroyBuffer(d, buf) + return nilBuffer, nilDeviceMemory, fmt.Errorf("vulkan: vkBindBufferMemory: %w", err) + } + return buf, mem, nil +} + +func DestroyBuffer(d Device, buf Buffer) { + C.vkDestroyBuffer(funcs.vkDestroyBuffer, d, buf, nil) +} + +func CreateShaderModule(d Device, spirv string) (ShaderModule, error) { + ptr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&spirv)).Data) + inf := C.VkShaderModuleCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + codeSize: C.size_t(len(spirv)), + pCode: (*C.uint32_t)(ptr), + } + + var mod C.VkShaderModule + if err := vkErr(C.vkCreateShaderModule(funcs.vkCreateShaderModule, d, inf, nil, &mod)); err != nil { + return nilShaderModule, fmt.Errorf("vulkan: vkCreateShaderModule: %w", err) + } + return mod, nil +} + +func DestroyShaderModule(d Device, mod ShaderModule) { + C.vkDestroyShaderModule(funcs.vkDestroyShaderModule, d, mod, nil) +} + +func CreateGraphicsPipeline(d Device, pass RenderPass, vmod, fmod ShaderModule, blend bool, srcFactor, dstFactor BlendFactor, topology PrimitiveTopology, bindings []VertexInputBindingDescription, attrs []VertexInputAttributeDescription, layout PipelineLayout) (Pipeline, error) { + main := C.CString("main") + defer C.free(unsafe.Pointer(main)) + stages := []C.VkPipelineShaderStageCreateInfo{ + { + sType: C.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + stage: C.VK_SHADER_STAGE_VERTEX_BIT, + module: vmod, + pName: main, + }, + { + sType: C.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + stage: C.VK_SHADER_STAGE_FRAGMENT_BIT, + module: fmod, + pName: main, + }, + } + dynStates := []C.VkDynamicState{C.VK_DYNAMIC_STATE_VIEWPORT} + dynInf := C.VkPipelineDynamicStateCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + dynamicStateCount: C.uint32_t(len(dynStates)), + pDynamicStates: &dynStates[0], + } + const maxDim = 0x7fffffff + scissors := []C.VkRect2D{{extent: C.VkExtent2D{width: maxDim, height: maxDim}}} + viewportInf := C.VkPipelineViewportStateCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + viewportCount: 1, + scissorCount: C.uint32_t(len(scissors)), + pScissors: &scissors[0], + } + enable := C.VkBool32(0) + if blend { + enable = 1 + } + attBlendInf := C.VkPipelineColorBlendAttachmentState{ + blendEnable: enable, + srcColorBlendFactor: srcFactor, + srcAlphaBlendFactor: srcFactor, + dstColorBlendFactor: dstFactor, + dstAlphaBlendFactor: dstFactor, + colorBlendOp: C.VK_BLEND_OP_ADD, + alphaBlendOp: C.VK_BLEND_OP_ADD, + colorWriteMask: C.VK_COLOR_COMPONENT_R_BIT | C.VK_COLOR_COMPONENT_G_BIT | C.VK_COLOR_COMPONENT_B_BIT | C.VK_COLOR_COMPONENT_A_BIT, + } + blendInf := C.VkPipelineColorBlendStateCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + attachmentCount: 1, + pAttachments: &attBlendInf, + } + var vkBinds []C.VkVertexInputBindingDescription + var vkAttrs []C.VkVertexInputAttributeDescription + for _, b := range bindings { + vkBinds = append(vkBinds, C.VkVertexInputBindingDescription{ + binding: C.uint32_t(b.Binding), + stride: C.uint32_t(b.Stride), + }) + } + for _, a := range attrs { + vkAttrs = append(vkAttrs, C.VkVertexInputAttributeDescription{ + location: C.uint32_t(a.Location), + binding: C.uint32_t(a.Binding), + format: a.Format, + offset: C.uint32_t(a.Offset), + }) + } + vertexInf := C.VkPipelineVertexInputStateCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + } + if n := len(vkBinds); n > 0 { + vertexInf.vertexBindingDescriptionCount = C.uint32_t(n) + vertexInf.pVertexBindingDescriptions = &vkBinds[0] + } + if n := len(vkAttrs); n > 0 { + vertexInf.vertexAttributeDescriptionCount = C.uint32_t(n) + vertexInf.pVertexAttributeDescriptions = &vkAttrs[0] + } + inf := C.VkGraphicsPipelineCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + stageCount: C.uint32_t(len(stages)), + pStages: &stages[0], + renderPass: pass, + layout: layout, + pRasterizationState: &C.VkPipelineRasterizationStateCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + lineWidth: 1.0, + }, + pMultisampleState: &C.VkPipelineMultisampleStateCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + rasterizationSamples: C.VK_SAMPLE_COUNT_1_BIT, + }, + pInputAssemblyState: &C.VkPipelineInputAssemblyStateCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + topology: topology, + }, + } + + var pipe C.VkPipeline + if err := vkErr(C.vkCreateGraphicsPipelines(funcs.vkCreateGraphicsPipelines, d, nilPipelineCache, inf, dynInf, blendInf, vertexInf, viewportInf, nil, &pipe)); err != nil { + return nilPipeline, fmt.Errorf("vulkan: vkCreateGraphicsPipelines: %w", err) + } + return pipe, nil +} + +func DestroyPipeline(d Device, p Pipeline) { + C.vkDestroyPipeline(funcs.vkDestroyPipeline, d, p, nil) +} + +func CreatePipelineLayout(d Device, pushRanges []PushConstantRange, sets []DescriptorSetLayout) (PipelineLayout, error) { + inf := C.VkPipelineLayoutCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + } + if n := len(sets); n > 0 { + inf.setLayoutCount = C.uint32_t(n) + inf.pSetLayouts = &sets[0] + } + if n := len(pushRanges); n > 0 { + inf.pushConstantRangeCount = C.uint32_t(n) + inf.pPushConstantRanges = &pushRanges[0] + } + var l C.VkPipelineLayout + if err := vkErr(C.vkCreatePipelineLayout(funcs.vkCreatePipelineLayout, d, inf, nil, &l)); err != nil { + return nilPipelineLayout, fmt.Errorf("vulkan: vkCreatePipelineLayout: %w", err) + } + return l, nil +} + +func DestroyPipelineLayout(d Device, l PipelineLayout) { + C.vkDestroyPipelineLayout(funcs.vkDestroyPipelineLayout, d, l, nil) +} + +func CreateDescriptorSetLayout(d Device, bindings []DescriptorSetLayoutBinding) (DescriptorSetLayout, error) { + var vkbinds []C.VkDescriptorSetLayoutBinding + for _, b := range bindings { + vkbinds = append(vkbinds, C.VkDescriptorSetLayoutBinding{ + binding: C.uint32_t(b.Binding), + descriptorType: b.DescriptorType, + descriptorCount: 1, + stageFlags: b.StageFlags, + }) + } + inf := C.VkDescriptorSetLayoutCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + } + if n := len(vkbinds); n > 0 { + inf.bindingCount = C.uint32_t(len(vkbinds)) + inf.pBindings = &vkbinds[0] + } + var l C.VkDescriptorSetLayout + if err := vkErr(C.vkCreateDescriptorSetLayout(funcs.vkCreateDescriptorSetLayout, d, inf, nil, &l)); err != nil { + return nilDescriptorSetLayout, fmt.Errorf("vulkan: vkCreateDescriptorSetLayout: %w", err) + } + return l, nil +} + +func DestroyDescriptorSetLayout(d Device, l DescriptorSetLayout) { + C.vkDestroyDescriptorSetLayout(funcs.vkDestroyDescriptorSetLayout, d, l, nil) +} + +func MapMemory(d Device, mem DeviceMemory, offset, size int) ([]byte, error) { + var ptr unsafe.Pointer + if err := vkErr(C.vkMapMemory(funcs.vkMapMemory, d, mem, C.VkDeviceSize(offset), C.VkDeviceSize(size), 0, &ptr)); err != nil { + return nil, fmt.Errorf("vulkan: vkMapMemory: %w", err) + } + return ((*[1 << 30]byte)(ptr))[:size:size], nil +} + +func UnmapMemory(d Device, mem DeviceMemory) { + C.vkUnmapMemory(funcs.vkUnmapMemory, d, mem) +} + +func ResetCommandBuffer(buf CommandBuffer) error { + if err := vkErr(C.vkResetCommandBuffer(funcs.vkResetCommandBuffer, buf, 0)); err != nil { + return fmt.Errorf("vulkan: vkResetCommandBuffer. %w", err) + } + return nil +} + +func CreateDescriptorPool(d Device, maxSets int, sizes []DescriptorPoolSize) (DescriptorPool, error) { + inf := C.VkDescriptorPoolCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + maxSets: C.uint32_t(maxSets), + poolSizeCount: C.uint32_t(len(sizes)), + pPoolSizes: &sizes[0], + } + var pool C.VkDescriptorPool + if err := vkErr(C.vkCreateDescriptorPool(funcs.vkCreateDescriptorPool, d, inf, nil, &pool)); err != nil { + return nilDescriptorPool, fmt.Errorf("vulkan: vkCreateDescriptorPool: %w", err) + } + return pool, nil +} + +func DestroyDescriptorPool(d Device, pool DescriptorPool) { + C.vkDestroyDescriptorPool(funcs.vkDestroyDescriptorPool, d, pool, nil) +} + +func ResetDescriptorPool(d Device, pool DescriptorPool) error { + if err := vkErr(C.vkResetDescriptorPool(funcs.vkResetDescriptorPool, d, pool, 0)); err != nil { + return fmt.Errorf("vulkan: vkResetDescriptorPool: %w", err) + } + return nil +} + +func UpdateDescriptorSet(d Device, write WriteDescriptorSet) { + C.vkUpdateDescriptorSets(funcs.vkUpdateDescriptorSets, d, write, 0, nil) +} + +func AllocateDescriptorSet(d Device, pool DescriptorPool, layout DescriptorSetLayout) (DescriptorSet, error) { + inf := C.VkDescriptorSetAllocateInfo{ + sType: C.VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + descriptorPool: pool, + descriptorSetCount: 1, + pSetLayouts: &layout, + } + var set C.VkDescriptorSet + if err := vkErr(C.vkAllocateDescriptorSets(funcs.vkAllocateDescriptorSets, d, inf, &set)); err != nil { + return nilDescriptorSet, fmt.Errorf("vulkan: vkAllocateDescriptorSets: %w", err) + } + return set, nil +} + +func CreateComputePipeline(d Device, mod ShaderModule, layout PipelineLayout) (Pipeline, error) { + main := C.CString("main") + defer C.free(unsafe.Pointer(main)) + inf := C.VkComputePipelineCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + stage: C.VkPipelineShaderStageCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + stage: C.VK_SHADER_STAGE_COMPUTE_BIT, + module: mod, + pName: main, + }, + layout: layout, + } + var pipe C.VkPipeline + if err := vkErr(C.vkCreateComputePipelines(funcs.vkCreateComputePipelines, d, nilPipelineCache, 1, &inf, nil, &pipe)); err != nil { + return nilPipeline, fmt.Errorf("vulkan: vkCreateComputePipelines: %w", err) + } + return pipe, nil +} + +func CreateFence(d Device) (Fence, error) { + inf := C.VkFenceCreateInfo{ + sType: C.VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + } + var f C.VkFence + if err := vkErr(C.vkCreateFence(funcs.vkCreateFence, d, &inf, nil, &f)); err != nil { + return nilFence, fmt.Errorf("vulkan: vkCreateFence: %w", err) + } + return f, nil +} + +func DestroyFence(d Device, f Fence) { + C.vkDestroyFence(funcs.vkDestroyFence, d, f, nil) +} + +func WaitForFences(d Device, fences ...Fence) error { + if len(fences) == 0 { + return nil + } + err := vkErr(C.vkWaitForFences(funcs.vkWaitForFences, d, C.uint32_t(len(fences)), &fences[0], C.VK_TRUE, 0xffffffffffffffff)) + if err != nil { + return fmt.Errorf("vulkan: vkWaitForFences: %w", err) + } + return nil +} + +func ResetFences(d Device, fences ...Fence) error { + if len(fences) == 0 { + return nil + } + err := vkErr(C.vkResetFences(funcs.vkResetFences, d, C.uint32_t(len(fences)), &fences[0])) + if err != nil { + return fmt.Errorf("vulkan: vkResetFences: %w", err) + } + return nil +} + +func BuildSubpassDependency(srcStage, dstStage PipelineStageFlags, srcMask, dstMask AccessFlags, flags DependencyFlags) SubpassDependency { + return C.VkSubpassDependency{ + srcSubpass: C.VK_SUBPASS_EXTERNAL, + srcStageMask: srcStage, + srcAccessMask: srcMask, + dstSubpass: 0, + dstStageMask: dstStage, + dstAccessMask: dstMask, + dependencyFlags: flags, + } +} + +func BuildPushConstantRange(stages ShaderStageFlags, offset, size int) PushConstantRange { + return C.VkPushConstantRange{ + stageFlags: stages, + offset: C.uint32_t(offset), + size: C.uint32_t(size), + } +} + +func BuildDescriptorPoolSize(typ DescriptorType, count int) DescriptorPoolSize { + return C.VkDescriptorPoolSize{ + _type: typ, + descriptorCount: C.uint32_t(count), + } +} + +func BuildWriteDescriptorSetImage(set DescriptorSet, binding int, typ DescriptorType, sampler Sampler, view ImageView, layout ImageLayout) WriteDescriptorSet { + return C.VkWriteDescriptorSet{ + sType: C.VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: set, + dstBinding: C.uint32_t(binding), + descriptorCount: 1, + descriptorType: typ, + pImageInfo: &C.VkDescriptorImageInfo{ + sampler: sampler, + imageView: view, + imageLayout: layout, + }, + } +} + +func BuildWriteDescriptorSetBuffer(set DescriptorSet, binding int, typ DescriptorType, buf Buffer) WriteDescriptorSet { + return C.VkWriteDescriptorSet{ + sType: C.VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + dstSet: set, + dstBinding: C.uint32_t(binding), + descriptorCount: 1, + descriptorType: typ, + pBufferInfo: &C.VkDescriptorBufferInfo{ + buffer: buf, + _range: C.VK_WHOLE_SIZE, + }, + } +} + +func (r PushConstantRange) StageFlags() ShaderStageFlags { + return r.stageFlags +} + +func (r PushConstantRange) Offset() int { + return int(r.offset) +} + +func (r PushConstantRange) Size() int { + return int(r.size) +} + +func (p QueueFamilyProperties) Flags() QueueFlags { + return p.queueFlags +} + +func (c SurfaceCapabilities) MinExtent() image.Point { + return image.Pt(int(c.minImageExtent.width), int(c.minImageExtent.height)) +} + +func (c SurfaceCapabilities) MaxExtent() image.Point { + return image.Pt(int(c.maxImageExtent.width), int(c.maxImageExtent.height)) +} + +func BuildViewport(x, y, width, height float32) Viewport { + return C.VkViewport{ + x: C.float(x), + y: C.float(y), + width: C.float(width), + height: C.float(height), + maxDepth: 1.0, + } +} + +func BuildImageMemoryBarrier(img Image, srcMask, dstMask AccessFlags, oldLayout, newLayout ImageLayout) ImageMemoryBarrier { + return C.VkImageMemoryBarrier{ + sType: C.VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + srcAccessMask: srcMask, + dstAccessMask: dstMask, + oldLayout: oldLayout, + newLayout: newLayout, + image: img, + subresourceRange: C.VkImageSubresourceRange{ + aspectMask: C.VK_IMAGE_ASPECT_COLOR_BIT, + levelCount: C.VK_REMAINING_MIP_LEVELS, + layerCount: C.VK_REMAINING_ARRAY_LAYERS, + }, + } +} + +func BuildBufferMemoryBarrier(buf Buffer, srcMask, dstMask AccessFlags) BufferMemoryBarrier { + return C.VkBufferMemoryBarrier{ + sType: C.VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + srcAccessMask: srcMask, + dstAccessMask: dstMask, + buffer: buf, + size: C.VK_WHOLE_SIZE, + } +} + +func BuildMemoryBarrier(srcMask, dstMask AccessFlags) MemoryBarrier { + return C.VkMemoryBarrier{ + sType: C.VK_STRUCTURE_TYPE_MEMORY_BARRIER, + srcAccessMask: srcMask, + dstAccessMask: dstMask, + } +} + +func BuildBufferImageCopy(bufOff, bufStride, x, y, width, height int) BufferImageCopy { + return C.VkBufferImageCopy{ + bufferOffset: C.VkDeviceSize(bufOff), + bufferRowLength: C.uint32_t(bufStride), + imageSubresource: C.VkImageSubresourceLayers{ + aspectMask: C.VK_IMAGE_ASPECT_COLOR_BIT, + layerCount: 1, + }, + imageOffset: C.VkOffset3D{ + x: C.int32_t(x), y: C.int32_t(y), z: 0, + }, + imageExtent: C.VkExtent3D{ + width: C.uint32_t(width), height: C.uint32_t(height), depth: 1, + }, + } +} + +func BuildImageCopy(srcX, srcY, dstX, dstY, width, height int) ImageCopy { + return C.VkImageCopy{ + srcSubresource: C.VkImageSubresourceLayers{ + aspectMask: C.VK_IMAGE_ASPECT_COLOR_BIT, + layerCount: 1, + }, + srcOffset: C.VkOffset3D{ + x: C.int32_t(srcX), + y: C.int32_t(srcY), + }, + dstSubresource: C.VkImageSubresourceLayers{ + aspectMask: C.VK_IMAGE_ASPECT_COLOR_BIT, + layerCount: 1, + }, + dstOffset: C.VkOffset3D{ + x: C.int32_t(dstX), + y: C.int32_t(dstY), + }, + extent: C.VkExtent3D{ + width: C.uint32_t(width), + height: C.uint32_t(height), + depth: 1, + }, + } +} + +func findMemoryTypeIndex(pd C.VkPhysicalDevice, constraints C.uint32_t, wantProps C.VkMemoryPropertyFlags) (int, bool) { + var memProps C.VkPhysicalDeviceMemoryProperties + C.vkGetPhysicalDeviceMemoryProperties(funcs.vkGetPhysicalDeviceMemoryProperties, pd, &memProps) + + for i := 0; i < int(memProps.memoryTypeCount); i++ { + if (constraints & (1 << i)) == 0 { + continue + } + if (memProps.memoryTypes[i].propertyFlags & wantProps) != wantProps { + continue + } + return i, true + } + + return 0, false +} + +func choosePresentMode(pd C.VkPhysicalDevice, surf Surface) (C.VkPresentModeKHR, bool, error) { + var count C.uint32_t + err := vkErr(C.vkGetPhysicalDeviceSurfacePresentModesKHR(funcs.vkGetPhysicalDeviceSurfacePresentModesKHR, pd, surf, &count, nil)) + if err != nil { + return 0, false, fmt.Errorf("vulkan: vkGetPhysicalDeviceSurfacePresentModesKHR: %w", err) + } + if count == 0 { + return 0, false, nil + } + modes := make([]C.VkPresentModeKHR, count) + err = vkErr(C.vkGetPhysicalDeviceSurfacePresentModesKHR(funcs.vkGetPhysicalDeviceSurfacePresentModesKHR, pd, surf, &count, &modes[0])) + if err != nil { + return 0, false, fmt.Errorf("vulkan: kGetPhysicalDeviceSurfacePresentModesKHR: %w", err) + } + for _, m := range modes { + if m == C.VK_PRESENT_MODE_MAILBOX_KHR || m == C.VK_PRESENT_MODE_FIFO_KHR { + return m, true, nil + } + } + return 0, false, nil +} + +func chooseFormat(pd C.VkPhysicalDevice, surf Surface) (C.VkSurfaceFormatKHR, bool, error) { + var count C.uint32_t + err := vkErr(C.vkGetPhysicalDeviceSurfaceFormatsKHR(funcs.vkGetPhysicalDeviceSurfaceFormatsKHR, pd, surf, &count, nil)) + if err != nil { + return C.VkSurfaceFormatKHR{}, false, fmt.Errorf("vulkan: vkGetPhysicalDeviceSurfaceFormatsKHR: %w", err) + } + if count == 0 { + return C.VkSurfaceFormatKHR{}, false, nil + } + formats := make([]C.VkSurfaceFormatKHR, count) + err = vkErr(C.vkGetPhysicalDeviceSurfaceFormatsKHR(funcs.vkGetPhysicalDeviceSurfaceFormatsKHR, pd, surf, &count, &formats[0])) + if err != nil { + return C.VkSurfaceFormatKHR{}, false, fmt.Errorf("vulkan: vkGetPhysicalDeviceSurfaceFormatsKHR: %w", err) + } + // Query for format with sRGB support. + // TODO: Support devices without sRGB. + for _, f := range formats { + if f.colorSpace != C.VK_COLOR_SPACE_SRGB_NONLINEAR_KHR { + continue + } + switch f.format { + case C.VK_FORMAT_B8G8R8A8_SRGB, C.VK_FORMAT_R8G8B8A8_SRGB: + return f, true, nil + } + } + return C.VkSurfaceFormatKHR{}, false, nil +} + +func chooseQueue(pd C.VkPhysicalDevice, surf Surface, flags C.VkQueueFlags) (int, bool, error) { + queues := GetPhysicalDeviceQueueFamilyProperties(pd) + for i, q := range queues { + // Check for presentation and feature support. + if q.queueFlags&flags != flags { + continue + } + if surf != nilSurface { + // Check for presentation support. It is possible that a device has no + // queue with both rendering and presentation support, but not in reality. + // See https://github.com/KhronosGroup/Vulkan-Docs/issues/1234. + var support C.VkBool32 + if err := vkErr(C.vkGetPhysicalDeviceSurfaceSupportKHR(funcs.vkGetPhysicalDeviceSurfaceSupportKHR, pd, C.uint32_t(i), surf, &support)); err != nil { + return 0, false, fmt.Errorf("vulkan: vkGetPhysicalDeviceSurfaceSupportKHR: %w", err) + } + if support != C.VK_TRUE { + continue + } + } + return i, true, nil + } + return 0, false, nil +} + +func dlsym(handle unsafe.Pointer, s string) unsafe.Pointer { + cs := C.CString(s) + defer C.free(unsafe.Pointer(cs)) + return C.dlsym(handle, cs) +} + +func dlopen(lib string) unsafe.Pointer { + clib := C.CString(lib) + defer C.free(unsafe.Pointer(clib)) + return C.dlopen(clib, C.RTLD_NOW|C.RTLD_LOCAL) +} + +func vkErr(res C.VkResult) error { + switch res { + case C.VK_SUCCESS: + return nil + default: + return Error(res) + } +} + +func (e Error) Error() string { + return fmt.Sprintf("error %d", e) +} diff --git a/vendor/gioui.org/internal/vk/vulkan_android.go b/vendor/gioui.org/internal/vk/vulkan_android.go new file mode 100644 index 0000000..143146e --- /dev/null +++ b/vendor/gioui.org/internal/vk/vulkan_android.go @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +//go:build !nowayland +// +build !nowayland + +package vk + +/* +#define VK_USE_PLATFORM_ANDROID_KHR +#define VK_NO_PROTOTYPES 1 +#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; +#include <android/native_window.h> +#include <vulkan/vulkan.h> + +static VkResult vkCreateAndroidSurfaceKHR(PFN_vkCreateAndroidSurfaceKHR f, VkInstance instance, const VkAndroidSurfaceCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) { + return f(instance, pCreateInfo, pAllocator, pSurface); +} +*/ +import "C" +import ( + "fmt" + "unsafe" +) + +var wlFuncs struct { + vkCreateAndroidSurfaceKHR C.PFN_vkCreateAndroidSurfaceKHR +} + +func init() { + loadFuncs = append(loadFuncs, func(dlopen func(name string) *[0]byte) { + wlFuncs.vkCreateAndroidSurfaceKHR = dlopen("vkCreateAndroidSurfaceKHR") + }) +} + +func CreateAndroidSurface(inst Instance, window unsafe.Pointer) (Surface, error) { + inf := C.VkAndroidSurfaceCreateInfoKHR{ + sType: C.VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, + window: (*C.ANativeWindow)(window), + } + var surf Surface + if err := vkErr(C.vkCreateAndroidSurfaceKHR(wlFuncs.vkCreateAndroidSurfaceKHR, inst, &inf, nil, &surf)); err != nil { + return 0, fmt.Errorf("vulkan: vkCreateAndroidSurfaceKHR: %w", err) + } + return surf, nil +} diff --git a/vendor/gioui.org/internal/vk/vulkan_wayland.go b/vendor/gioui.org/internal/vk/vulkan_wayland.go new file mode 100644 index 0000000..cb057bc --- /dev/null +++ b/vendor/gioui.org/internal/vk/vulkan_wayland.go @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +//go:build ((linux && !android) || freebsd) && !nowayland +// +build linux,!android freebsd +// +build !nowayland + +package vk + +/* +#define VK_USE_PLATFORM_WAYLAND_KHR +#define VK_NO_PROTOTYPES 1 +#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; +#include <vulkan/vulkan.h> + +static VkResult vkCreateWaylandSurfaceKHR(PFN_vkCreateWaylandSurfaceKHR f, VkInstance instance, const VkWaylandSurfaceCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) { + return f(instance, pCreateInfo, pAllocator, pSurface); +} +*/ +import "C" +import ( + "fmt" + "unsafe" +) + +var wlFuncs struct { + vkCreateWaylandSurfaceKHR C.PFN_vkCreateWaylandSurfaceKHR +} + +func init() { + loadFuncs = append(loadFuncs, func(dlopen func(name string) *[0]byte) { + wlFuncs.vkCreateWaylandSurfaceKHR = dlopen("vkCreateWaylandSurfaceKHR") + }) +} + +func CreateWaylandSurface(inst Instance, disp unsafe.Pointer, wlSurf unsafe.Pointer) (Surface, error) { + inf := C.VkWaylandSurfaceCreateInfoKHR{ + sType: C.VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, + display: (*C.struct_wl_display)(disp), + surface: (*C.struct_wl_surface)(wlSurf), + } + var surf Surface + if err := vkErr(C.vkCreateWaylandSurfaceKHR(wlFuncs.vkCreateWaylandSurfaceKHR, inst, &inf, nil, &surf)); err != nil { + return 0, fmt.Errorf("vulkan: vkCreateWaylandSurfaceKHR: %w", err) + } + return surf, nil +} diff --git a/vendor/gioui.org/internal/vk/vulkan_x11.go b/vendor/gioui.org/internal/vk/vulkan_x11.go new file mode 100644 index 0000000..780a5d5 --- /dev/null +++ b/vendor/gioui.org/internal/vk/vulkan_x11.go @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +//go:build ((linux && !android) || freebsd) && !nox11 +// +build linux,!android freebsd +// +build !nox11 + +package vk + +/* +#define VK_USE_PLATFORM_XLIB_KHR +#define VK_NO_PROTOTYPES 1 +#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; +#include <vulkan/vulkan.h> + +static VkResult vkCreateXlibSurfaceKHR(PFN_vkCreateXlibSurfaceKHR f, VkInstance instance, const VkXlibSurfaceCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) { + return f(instance, pCreateInfo, pAllocator, pSurface); +} +*/ +import "C" +import ( + "fmt" + "unsafe" +) + +var x11Funcs struct { + vkCreateXlibSurfaceKHR C.PFN_vkCreateXlibSurfaceKHR +} + +func init() { + loadFuncs = append(loadFuncs, func(dlopen func(name string) *[0]byte) { + x11Funcs.vkCreateXlibSurfaceKHR = dlopen("vkCreateXlibSurfaceKHR") + }) +} + +func CreateXlibSurface(inst Instance, dpy unsafe.Pointer, window uintptr) (Surface, error) { + inf := C.VkXlibSurfaceCreateInfoKHR{ + sType: C.VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, + dpy: (*C.Display)(dpy), + window: (C.Window)(window), + } + var surf Surface + if err := vkErr(C.vkCreateXlibSurfaceKHR(x11Funcs.vkCreateXlibSurfaceKHR, inst, &inf, nil, &surf)); err != nil { + return 0, fmt.Errorf("vulkan: vkCreateXlibSurfaceKHR: %w", err) + } + return surf, nil +} |