ebiten/internal/graphicsdriver/directx/dxgi_windows.go

592 lines
19 KiB
Go

// Copyright 2023 The Ebitengine Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package directx
import (
"fmt"
"runtime"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
type _DXGI_ALPHA_MODE uint32
const (
_DXGI_ALPHA_MODE_UNSPECIFIED _DXGI_ALPHA_MODE = 0
_DXGI_ALPHA_MODE_PREMULTIPLIED _DXGI_ALPHA_MODE = 1
_DXGI_ALPHA_MODE_STRAIGHT _DXGI_ALPHA_MODE = 2
_DXGI_ALPHA_MODE_IGNORE _DXGI_ALPHA_MODE = 3
_DXGI_ALPHA_MODE_FORCE_DWORD _DXGI_ALPHA_MODE = 0xffffffff
)
type _DXGI_COLOR_SPACE_TYPE int32
type _DXGI_FEATURE int32
const (
_DXGI_FEATURE_PRESENT_ALLOW_TEARING _DXGI_FEATURE = 0
)
type _DXGI_FORMAT int32
const (
_DXGI_FORMAT_UNKNOWN _DXGI_FORMAT = 0
_DXGI_FORMAT_R32G32B32A32_FLOAT _DXGI_FORMAT = 2
_DXGI_FORMAT_R32G32_FLOAT _DXGI_FORMAT = 16
_DXGI_FORMAT_R8G8B8A8_UNORM _DXGI_FORMAT = 28
_DXGI_FORMAT_D24_UNORM_S8_UINT _DXGI_FORMAT = 45
_DXGI_FORMAT_R16_UINT _DXGI_FORMAT = 57
_DXGI_FORMAT_B8G8R8A8_UNORM _DXGI_FORMAT = 87
)
type _DXGI_MODE_SCANLINE_ORDER int32
type _DXGI_MODE_SCALING int32
type _DXGI_PRESENT uint32
const (
_DXGI_PRESENT_TEST _DXGI_PRESENT = 0x00000001
_DXGI_PRESENT_ALLOW_TEARING _DXGI_PRESENT = 0x00000200
)
type _DXGI_SCALING int32
type _DXGI_SWAP_CHAIN_FLAG int32
const (
_DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING _DXGI_SWAP_CHAIN_FLAG = 2048
)
type _DXGI_SWAP_EFFECT int32
const (
_DXGI_SWAP_EFFECT_FLIP_DISCARD _DXGI_SWAP_EFFECT = 4
)
type _DXGI_USAGE uint32
const (
_DXGI_USAGE_RENDER_TARGET_OUTPUT _DXGI_USAGE = 1 << (1 + 4)
)
const (
_DXGI_ADAPTER_FLAG_SOFTWARE = 2
_DXGI_CREATE_FACTORY_DEBUG = 0x01
_DXGI_ERROR_NOT_FOUND = handleError(0x887A0002)
_DXGI_MWA_NO_ALT_ENTER = 0x2
_DXGI_MWA_NO_WINDOW_CHANGES = 0x1
)
var (
_IID_IDXGIAdapter1 = windows.GUID{Data1: 0x29038f61, Data2: 0x3839, Data3: 0x4626, Data4: [...]byte{0x91, 0xfd, 0x08, 0x68, 0x79, 0x01, 0x1a, 0x05}}
_IID_IDXGIDevice = windows.GUID{Data1: 0x54ec77fa, Data2: 0x1377, Data3: 0x44e6, Data4: [...]byte{0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8, 0x4c}}
_IID_IDXGIFactory4 = windows.GUID{Data1: 0x1bc6ea02, Data2: 0xef36, Data3: 0x464f, Data4: [...]byte{0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a}}
_IID_IDXGIFactory5 = windows.GUID{Data1: 0x7632e1f5, Data2: 0xee65, Data3: 0x4dca, Data4: [...]byte{0x87, 0xfd, 0x84, 0xcd, 0x75, 0xf8, 0x83, 0x8d}}
)
var (
dxgi = windows.NewLazySystemDLL("dxgi.dll")
procCreateDXGIFactory2 = dxgi.NewProc("CreateDXGIFactory2")
)
func _CreateDXGIFactory2(flags uint32) (*_IDXGIFactory4, error) {
var factory *_IDXGIFactory4
r, _, _ := procCreateDXGIFactory2.Call(uintptr(flags), uintptr(unsafe.Pointer(&_IID_IDXGIFactory4)), uintptr(unsafe.Pointer(&factory)))
if uint32(r) != uint32(windows.S_OK) {
return nil, fmt.Errorf("directx: CreateDXGIFactory2 failed: %w", handleError(windows.Handle(uint32(r))))
}
return factory, nil
}
type _DXGI_ADAPTER_DESC1 struct {
Description [128]uint16
VendorId uint32
DeviceId uint32
SubSysId uint32
Revision uint32
DedicatedVideoMemory uint
DedicatedSystemMemory uint
SharedSystemMemory uint
AdapterLuid _LUID
Flags uint32
}
type _DXGI_SWAP_CHAIN_FULLSCREEN_DESC struct {
RefreshRate _DXGI_RATIONAL
ScanlineOrdering _DXGI_MODE_SCANLINE_ORDER
Scaling _DXGI_MODE_SCALING
Windowed _BOOL
}
type _DXGI_RATIONAL struct {
Numerator uint32
Denominator uint32
}
type _DXGI_SAMPLE_DESC struct {
Count uint32
Quality uint32
}
type _DXGI_SWAP_CHAIN_DESC1 struct {
Width uint32
Height uint32
Format _DXGI_FORMAT
Stereo _BOOL
SampleDesc _DXGI_SAMPLE_DESC
BufferUsage _DXGI_USAGE
BufferCount uint32
Scaling _DXGI_SCALING
SwapEffect _DXGI_SWAP_EFFECT
AlphaMode _DXGI_ALPHA_MODE
Flags uint32
}
type _LUID struct {
LowPart uint32
HighPart int32
}
type _IDXGIAdapter struct {
vtbl *_IDXGIAdapter1_Vtbl
}
type _IDXGIAdapter_Vtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
SetPrivateData uintptr
SetPrivateDataInterface uintptr
GetPrivateData uintptr
GetParent uintptr
EnumOutputs uintptr
GetDesc uintptr
CheckInterfaceSupport uintptr
}
func (i *_IDXGIAdapter) EnumOutputs(output uint32) (*_IDXGIOutput, error) {
var pOutput *_IDXGIOutput
r, _, _ := syscall.Syscall(i.vtbl.EnumOutputs, 3, uintptr(unsafe.Pointer(i)), uintptr(output), uintptr(unsafe.Pointer(&pOutput)))
if uint32(r) != uint32(windows.S_OK) {
return nil, fmt.Errorf("directx: IDXGIAdapter::EnumOutputs failed: %w", handleError(windows.Handle(uint32(r))))
}
return pOutput, nil
}
func (i *_IDXGIAdapter) Release() uint32 {
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
return uint32(r)
}
type _IDXGIAdapter1 struct {
vtbl *_IDXGIAdapter1_Vtbl
}
type _IDXGIAdapter1_Vtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
SetPrivateData uintptr
SetPrivateDataInterface uintptr
GetPrivateData uintptr
GetParent uintptr
EnumOutputs uintptr
GetDesc uintptr
CheckInterfaceSupport uintptr
GetDesc1 uintptr
}
func (i *_IDXGIAdapter1) Release() uint32 {
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
return uint32(r)
}
func (i *_IDXGIAdapter1) GetDesc1() (*_DXGI_ADAPTER_DESC1, error) {
var desc _DXGI_ADAPTER_DESC1
r, _, _ := syscall.Syscall(i.vtbl.GetDesc1, 2, uintptr(unsafe.Pointer(i)), uintptr(unsafe.Pointer(&desc)), 0)
if uint32(r) != uint32(windows.S_OK) {
return nil, fmt.Errorf("directx: IDXGIAdapter1::GetDesc1 failed: %w", handleError(windows.Handle(uint32(r))))
}
return &desc, nil
}
type _IDXGIDevice struct {
vtbl *_IDXGIDevice_Vtbl
}
type _IDXGIDevice_Vtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
SetPrivateData uintptr
SetPrivateDataInterface uintptr
GetPrivateData uintptr
GetParent uintptr
GetAdapter uintptr
CreateSurface uintptr
QueryResourceResidency uintptr
SetGPUThreadPriority uintptr
GetGPUThreadPriority uintptr
}
func (i *_IDXGIDevice) GetAdapter() (*_IDXGIAdapter, error) {
var adapter *_IDXGIAdapter
r, _, _ := syscall.Syscall(i.vtbl.GetAdapter, 2, uintptr(unsafe.Pointer(i)), uintptr(unsafe.Pointer(&adapter)), 0)
if uint32(r) != uint32(windows.S_OK) {
return nil, fmt.Errorf("directx: IDXGIDevice::GetAdapter failed: %w", handleError(windows.Handle(uint32(r))))
}
return adapter, nil
}
func (i *_IDXGIDevice) Release() uint32 {
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
return uint32(r)
}
type _IDXGIFactory4 struct {
vtbl *_IDXGIFactory4_Vtbl
}
type _IDXGIFactory4_Vtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
SetPrivateData uintptr
SetPrivateDataInterface uintptr
GetPrivateData uintptr
GetParent uintptr
EnumAdapters uintptr
MakeWindowAssociation uintptr
GetWindowAssociation uintptr
CreateSwapChain uintptr
CreateSoftwareAdapter uintptr
EnumAdapters1 uintptr
IsCurrent uintptr
IsWindowedStereoEnabled uintptr
CreateSwapChainForHwnd uintptr
CreateSwapChainForCoreWindow uintptr
GetSharedResourceAdapterLuid uintptr
RegisterStereoStatusWindow uintptr
RegisterStereoStatusEvent uintptr
UnregisterStereoStatus uintptr
RegisterOcclusionStatusWindow uintptr
RegisterOcclusionStatusEvent uintptr
UnregisterOcclusionStatus uintptr
CreateSwapChainForComposition uintptr
GetCreationFlags uintptr
EnumAdapterByLuid uintptr
EnumWarpAdapter uintptr
}
func (i *_IDXGIFactory4) CreateSwapChainForComposition(pDevice unsafe.Pointer, pDesc *_DXGI_SWAP_CHAIN_DESC1, pRestrictToOutput *_IDXGIOutput) (*_IDXGISwapChain1, error) {
var swapChain *_IDXGISwapChain1
r, _, _ := syscall.Syscall6(i.vtbl.CreateSwapChainForComposition, 5,
uintptr(unsafe.Pointer(i)), uintptr(pDevice), uintptr(unsafe.Pointer(pDesc)),
uintptr(unsafe.Pointer(pRestrictToOutput)), uintptr(unsafe.Pointer(&swapChain)), 0)
runtime.KeepAlive(pDesc)
runtime.KeepAlive(pRestrictToOutput)
if uint32(r) != uint32(windows.S_OK) {
return nil, fmt.Errorf("directx: IDXGIFactory4::CreateSwapChainForComposition failed: %w", handleError(windows.Handle(uint32(r))))
}
return swapChain, nil
}
func (i *_IDXGIFactory4) CreateSwapChainForHwnd(pDevice unsafe.Pointer, hWnd windows.HWND, pDesc *_DXGI_SWAP_CHAIN_DESC1, pFullscreenDesc *_DXGI_SWAP_CHAIN_FULLSCREEN_DESC, pRestrictToOutput *_IDXGIOutput) (*_IDXGISwapChain1, error) {
var swapChain *_IDXGISwapChain1
r, _, _ := syscall.Syscall9(i.vtbl.CreateSwapChainForHwnd, 7,
uintptr(unsafe.Pointer(i)), uintptr(pDevice), uintptr(hWnd),
uintptr(unsafe.Pointer(pDesc)), uintptr(unsafe.Pointer(pFullscreenDesc)), uintptr(unsafe.Pointer(pRestrictToOutput)),
uintptr(unsafe.Pointer(&swapChain)), 0, 0)
runtime.KeepAlive(pDesc)
runtime.KeepAlive(pFullscreenDesc)
runtime.KeepAlive(pRestrictToOutput)
if uint32(r) != uint32(windows.S_OK) {
return nil, fmt.Errorf("directx: IDXGIFactory4::CreateSwapChainForHwnd failed: %w", handleError(windows.Handle(uint32(r))))
}
return swapChain, nil
}
func (i *_IDXGIFactory4) EnumAdapters1(adapter uint32) (*_IDXGIAdapter1, error) {
var ptr *_IDXGIAdapter1
r, _, _ := syscall.Syscall(i.vtbl.EnumAdapters1, 3, uintptr(unsafe.Pointer(i)), uintptr(adapter), uintptr(unsafe.Pointer(&ptr)))
if uint32(r) != uint32(windows.S_OK) {
return nil, fmt.Errorf("directx: IDXGIFactory4::EnumAdapters1 failed: %w", handleError(windows.Handle(uint32(r))))
}
return ptr, nil
}
func (i *_IDXGIFactory4) EnumWarpAdapter() (*_IDXGIAdapter1, error) {
var ptr *_IDXGIAdapter1
r, _, _ := syscall.Syscall(i.vtbl.EnumWarpAdapter, 3, uintptr(unsafe.Pointer(i)), uintptr(unsafe.Pointer(&_IID_IDXGIAdapter1)), uintptr(unsafe.Pointer(&ptr)))
if uint32(r) != uint32(windows.S_OK) {
return nil, fmt.Errorf("directx: IDXGIFactory4::EnumWarpAdapter failed: %w", handleError(windows.Handle(uint32(r))))
}
return ptr, nil
}
func (i *_IDXGIFactory4) MakeWindowAssociation(windowHandle windows.HWND, flags uint32) error {
r, _, _ := syscall.Syscall(i.vtbl.MakeWindowAssociation, 3, uintptr(unsafe.Pointer(i)), uintptr(windowHandle), uintptr(flags))
if uint32(r) != uint32(windows.S_OK) {
return fmt.Errorf("directx: IDXGIFactory4::MakeWIndowAssociation failed: %w", handleError(windows.Handle(uint32(r))))
}
return nil
}
func (i *_IDXGIFactory4) QueryInterface(riid *windows.GUID) (unsafe.Pointer, error) {
var v unsafe.Pointer
r, _, _ := syscall.Syscall(i.vtbl.QueryInterface, 3, uintptr(unsafe.Pointer(i)), uintptr(unsafe.Pointer(riid)), uintptr(unsafe.Pointer(&v)))
runtime.KeepAlive(riid)
if uint32(r) != uint32(windows.S_OK) {
return nil, fmt.Errorf("directx: IDXGIFactory4::QueryInterface failed: %w", handleError(windows.Handle(uint32(r))))
}
return v, nil
}
func (i *_IDXGIFactory4) Release() uint32 {
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
return uint32(r)
}
type _IDXGIFactory5 struct {
vtbl *_IDXGIFactory5_Vtbl
}
type _IDXGIFactory5_Vtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
SetPrivateData uintptr
SetPrivateDataInterface uintptr
GetPrivateData uintptr
GetParent uintptr
EnumAdapters uintptr
MakeWindowAssociation uintptr
GetWindowAssociation uintptr
CreateSwapChain uintptr
CreateSoftwareAdapter uintptr
EnumAdapters1 uintptr
IsCurrent uintptr
IsWindowedStereoEnabled uintptr
CreateSwapChainForHwnd uintptr
CreateSwapChainForCoreWindow uintptr
GetSharedResourceAdapterLuid uintptr
RegisterStereoStatusWindow uintptr
RegisterStereoStatusEvent uintptr
UnregisterStereoStatus uintptr
RegisterOcclusionStatusWindow uintptr
RegisterOcclusionStatusEvent uintptr
UnregisterOcclusionStatus uintptr
CreateSwapChainForComposition uintptr
GetCreationFlags uintptr
EnumAdapterByLuid uintptr
EnumWarpAdapter uintptr
CheckFeatureSupport uintptr
}
func (i *_IDXGIFactory5) CheckFeatureSupport(feature _DXGI_FEATURE, pFeatureSupportData unsafe.Pointer, featureSupportDataSize uint32) error {
r, _, _ := syscall.Syscall6(i.vtbl.CheckFeatureSupport, 4, uintptr(unsafe.Pointer(i)),
uintptr(feature), uintptr(pFeatureSupportData), uintptr(featureSupportDataSize),
0, 0)
runtime.KeepAlive(pFeatureSupportData)
if uint32(r) != uint32(windows.S_OK) {
return fmt.Errorf("directx: IDXGIFactory5::CheckFeatureSupport failed: %w", handleError(windows.Handle(uint32(r))))
}
return nil
}
func (i *_IDXGIFactory5) Release() uint32 {
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
return uint32(r)
}
type _IDXGIOutput struct {
vtbl *_IDXGIOutput_Vtbl
}
type _IDXGIOutput_Vtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
SetPrivateData uintptr
SetPrivateDataInterface uintptr
GetPrivateData uintptr
GetParent uintptr
GetDesc uintptr
GetDisplayModeList uintptr
FindClosestMatchingMode uintptr
WaitForVBlank uintptr
TakeOwnership uintptr
ReleaseOwnership uintptr
GetGammaControlCapabilities uintptr
SetGammaControl uintptr
GetGammaControl uintptr
SetDisplaySurface uintptr
GetDisplaySurfaceData uintptr
GetFrameStatistics uintptr
}
func (i *_IDXGIOutput) Release() uint32 {
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
return uint32(r)
}
type _IDXGISwapChain1 struct {
vtbl *_IDXGISwapChain1_Vtbl
}
type _IDXGISwapChain1_Vtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
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
GetDesc1 uintptr
GetFullscreenDesc uintptr
GetHwnd uintptr
GetCoreWindow uintptr
Present1 uintptr
IsTemporaryMonoSupported uintptr
GetRestrictToOutput uintptr
SetBackgroundColor uintptr
GetBackgroundColor uintptr
SetRotation uintptr
GetRotation uintptr
}
func (i *_IDXGISwapChain1) As(swapChain **_IDXGISwapChain4) {
*swapChain = (*_IDXGISwapChain4)(unsafe.Pointer(i))
}
type _IDXGISwapChain4 struct {
vtbl *_IDXGISwapChain4_Vtbl
}
type _IDXGISwapChain4_Vtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
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
GetDesc1 uintptr
GetFullscreenDesc uintptr
GetHwnd uintptr
GetCoreWindow uintptr
Present1 uintptr
IsTemporaryMonoSupported uintptr
GetRestrictToOutput uintptr
SetBackgroundColor uintptr
GetBackgroundColor uintptr
SetRotation uintptr
GetRotation uintptr
SetSourceSize uintptr
GetSourceSize uintptr
SetMaximumFrameLatency uintptr
GetMaximumFrameLatency uintptr
GetFrameLatencyWaitableObject uintptr
SetMatrixTransform uintptr
GetMatrixTransform uintptr
GetCurrentBackBufferIndex uintptr
CheckColorSpaceSupport uintptr
SetColorSpace1 uintptr
ResizeBuffers1 uintptr
SetHDRMetaData uintptr
}
func (i *_IDXGISwapChain4) GetBuffer(buffer uint32, riid *windows.GUID) (unsafe.Pointer, error) {
var resource unsafe.Pointer
r, _, _ := syscall.Syscall6(i.vtbl.GetBuffer, 4, uintptr(unsafe.Pointer(i)),
uintptr(buffer), uintptr(unsafe.Pointer(riid)), uintptr(unsafe.Pointer(&resource)),
0, 0)
runtime.KeepAlive(riid)
if uint32(r) != uint32(windows.S_OK) {
return nil, fmt.Errorf("directx: IDXGISwapChain4::GetBuffer failed: %w", handleError(windows.Handle(uint32(r))))
}
return resource, nil
}
func (i *_IDXGISwapChain4) GetCurrentBackBufferIndex() uint32 {
r, _, _ := syscall.Syscall(i.vtbl.GetCurrentBackBufferIndex, 1, uintptr(unsafe.Pointer(i)), 0, 0)
return uint32(r)
}
func (i *_IDXGISwapChain4) Present(syncInterval uint32, flags uint32) (occluded bool, err error) {
r, _, _ := syscall.Syscall(i.vtbl.Present, 3, uintptr(unsafe.Pointer(i)), uintptr(syncInterval), uintptr(flags))
if uint32(r) != uint32(windows.S_OK) {
// During a screen lock, Present fails (#2179).
if uint32(r) == uint32(windows.DXGI_STATUS_OCCLUDED) {
return true, nil
}
return false, fmt.Errorf("directx: IDXGISwapChain4::Present failed: %w", handleError(windows.Handle(uint32(r))))
}
return false, nil
}
func (i *_IDXGISwapChain4) ResizeBuffers(bufferCount uint32, width uint32, height uint32, newFormat _DXGI_FORMAT, swapChainFlags uint32) error {
r, _, _ := syscall.Syscall6(i.vtbl.ResizeBuffers, 6,
uintptr(unsafe.Pointer(i)), uintptr(bufferCount), uintptr(width),
uintptr(height), uintptr(newFormat), uintptr(swapChainFlags))
if uint32(r) != uint32(windows.S_OK) {
return fmt.Errorf("directx: IDXGISwapChain4::ResizeBuffers failed: %w", handleError(windows.Handle(uint32(r))))
}
return nil
}
func (i *_IDXGISwapChain4) Release() uint32 {
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
return uint32(r)
}