mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
internal/graphicsdriver/directx: implement suspend/resume for Xbox
This commit is contained in:
parent
8dc582aca4
commit
de8184ac10
@ -1011,12 +1011,18 @@ type _D3D12XBOX_WAIT_FRAME_OBJECT_LIST struct {
|
|||||||
pSignaledObjectIndex *uint32
|
pSignaledObjectIndex *uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type _PAPPSTATE_CHANGE_ROUTINE func(quiesced bool, context unsafe.Pointer) uintptr
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// https://github.com/MicrosoftDocs/sdk-api/blob/docs/sdk-api-src/content/appnotify/nf-appnotify-registerappstatechangenotification.md
|
||||||
|
appnotify = windows.NewLazySystemDLL("API-MS-Win-Core-psm-appnotify-l1-1-0.dll")
|
||||||
d3d12 = windows.NewLazySystemDLL("d3d12.dll")
|
d3d12 = windows.NewLazySystemDLL("d3d12.dll")
|
||||||
d3d12x = windows.NewLazySystemDLL(microsoftgdk.D3D12DLLName())
|
d3d12x = windows.NewLazySystemDLL(microsoftgdk.D3D12DLLName())
|
||||||
d3dcompiler = windows.NewLazySystemDLL("d3dcompiler_47.dll")
|
d3dcompiler = windows.NewLazySystemDLL("d3dcompiler_47.dll")
|
||||||
dxgi = windows.NewLazySystemDLL("dxgi.dll")
|
dxgi = windows.NewLazySystemDLL("dxgi.dll")
|
||||||
|
|
||||||
|
procRegisterAppStateChangeNotification = appnotify.NewProc("RegisterAppStateChangeNotification")
|
||||||
|
|
||||||
procD3D12CreateDevice = d3d12.NewProc("D3D12CreateDevice")
|
procD3D12CreateDevice = d3d12.NewProc("D3D12CreateDevice")
|
||||||
procD3D12GetDebugInterface = d3d12.NewProc("D3D12GetDebugInterface")
|
procD3D12GetDebugInterface = d3d12.NewProc("D3D12GetDebugInterface")
|
||||||
procD3D12SerializeRootSignature = d3d12.NewProc("D3D12SerializeRootSignature")
|
procD3D12SerializeRootSignature = d3d12.NewProc("D3D12SerializeRootSignature")
|
||||||
@ -1115,6 +1121,16 @@ func _D3DCompile(srcData []byte, sourceName string, pDefines []_D3D_SHADER_MACRO
|
|||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _RegisterAppStateChangeNotification(routine _PAPPSTATE_CHANGE_ROUTINE, context unsafe.Pointer) (unsafe.Pointer, error) {
|
||||||
|
cb := windows.NewCallback(routine)
|
||||||
|
var registration unsafe.Pointer
|
||||||
|
r, _, _ := procRegisterAppStateChangeNotification.Call(cb, uintptr(context), uintptr(unsafe.Pointer(®istration)))
|
||||||
|
if windows.Errno(r) != windows.ERROR_SUCCESS {
|
||||||
|
return nil, fmt.Errorf("directx: RegisterAppStateChangeNotification failed: %w", windows.Errno(r))
|
||||||
|
}
|
||||||
|
return registration, nil
|
||||||
|
}
|
||||||
|
|
||||||
func _CreateDXGIFactory2(flags uint32) (*_IDXGIFactory4, error) {
|
func _CreateDXGIFactory2(flags uint32) (*_IDXGIFactory4, error) {
|
||||||
var factory *_IDXGIFactory4
|
var factory *_IDXGIFactory4
|
||||||
r, _, _ := procCreateDXGIFactory2.Call(uintptr(flags), uintptr(unsafe.Pointer(&_IID_IDXGIFactory4)), uintptr(unsafe.Pointer(&factory)))
|
r, _, _ := procCreateDXGIFactory2.Call(uintptr(flags), uintptr(unsafe.Pointer(&_IID_IDXGIFactory4)), uintptr(unsafe.Pointer(&factory)))
|
||||||
@ -1296,8 +1312,8 @@ type _ID3D12CommandQueue_Vtbl struct {
|
|||||||
// These members are for Xbox.
|
// These members are for Xbox.
|
||||||
_ uintptr
|
_ uintptr
|
||||||
_ uintptr
|
_ uintptr
|
||||||
_ uintptr
|
SuspendX uintptr
|
||||||
_ uintptr
|
ResumeX uintptr
|
||||||
_ uintptr
|
_ uintptr
|
||||||
_ uintptr
|
_ uintptr
|
||||||
_ uintptr
|
_ uintptr
|
||||||
@ -1326,6 +1342,18 @@ func (i *_ID3D12CommandQueue) PresentX(planeCount uint32, pPlaneParameters *_D3D
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *_ID3D12CommandQueue) Release() uint32 {
|
||||||
|
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
||||||
|
return uint32(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *_ID3D12CommandQueue) ResumeX() error {
|
||||||
|
if r, _, _ := syscall.Syscall(i.vtbl.ResumeX, 1, uintptr(unsafe.Pointer(i)), 0, 0); uint32(r) != uint32(windows.S_OK) {
|
||||||
|
return fmt.Errorf("directx: ID3D12CommandQueue::ResumeX failed: %w", handleError(windows.Handle(uint32(r))))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (i *_ID3D12CommandQueue) Signal(signal *_ID3D12Fence, value uint64) error {
|
func (i *_ID3D12CommandQueue) Signal(signal *_ID3D12Fence, value uint64) error {
|
||||||
var r uintptr
|
var r uintptr
|
||||||
if is64bit {
|
if is64bit {
|
||||||
@ -1342,9 +1370,11 @@ func (i *_ID3D12CommandQueue) Signal(signal *_ID3D12Fence, value uint64) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *_ID3D12CommandQueue) Release() uint32 {
|
func (i *_ID3D12CommandQueue) SuspendX(flags uint32) error {
|
||||||
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
if r, _, _ := syscall.Syscall(i.vtbl.SuspendX, 2, uintptr(unsafe.Pointer(i)), uintptr(flags), 0); uint32(r) != uint32(windows.S_OK) {
|
||||||
return uint32(r)
|
return fmt.Errorf("directx: ID3D12CommandQueue::SuspendX failed: %w", handleError(windows.Handle(uint32(r))))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type _ID3D12Debug struct {
|
type _ID3D12Debug struct {
|
||||||
|
@ -150,6 +150,10 @@ type Graphics struct {
|
|||||||
newScreenWidth int
|
newScreenWidth int
|
||||||
newScreenHeight int
|
newScreenHeight int
|
||||||
|
|
||||||
|
suspendingCh chan struct{}
|
||||||
|
suspendedCh chan struct{}
|
||||||
|
resumeCh chan struct{}
|
||||||
|
|
||||||
pipelineStates
|
pipelineStates
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,11 +345,35 @@ func (g *Graphics) initializeXbox(useWARP bool, useDebugLayer bool) (ferr error)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
dd, err := g.device.QueryInterface(&_IID_IDXGIDevice)
|
if err := g.registerFrameEventForXbox(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
g.suspendingCh = make(chan struct{})
|
||||||
|
g.suspendedCh = make(chan struct{})
|
||||||
|
g.resumeCh = make(chan struct{})
|
||||||
|
if _, err := _RegisterAppStateChangeNotification(func(quiesced bool, context unsafe.Pointer) uintptr {
|
||||||
|
if quiesced {
|
||||||
|
g.suspendingCh <- struct{}{}
|
||||||
|
// Confirm the suspension completed before the callback ends.
|
||||||
|
<-g.suspendedCh
|
||||||
|
} else {
|
||||||
|
g.resumeCh <- struct{}{}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Graphics) registerFrameEventForXbox() error {
|
||||||
|
d, err := g.device.QueryInterface(&_IID_IDXGIDevice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dxgiDevice := (*_IDXGIDevice)(dd)
|
dxgiDevice := (*_IDXGIDevice)(d)
|
||||||
defer dxgiDevice.Release()
|
defer dxgiDevice.Release()
|
||||||
|
|
||||||
dxgiAdapter, err := dxgiDevice.GetAdapter()
|
dxgiAdapter, err := dxgiDevice.GetAdapter()
|
||||||
@ -727,6 +755,22 @@ func (g *Graphics) SetWindow(window uintptr) {
|
|||||||
|
|
||||||
func (g *Graphics) Begin() error {
|
func (g *Graphics) Begin() error {
|
||||||
if microsoftgdk.IsXbox() && !g.frameStarted {
|
if microsoftgdk.IsXbox() && !g.frameStarted {
|
||||||
|
select {
|
||||||
|
case <-g.suspendingCh:
|
||||||
|
if err := g.commandQueue.SuspendX(0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g.suspendedCh <- struct{}{}
|
||||||
|
<-g.resumeCh
|
||||||
|
if err := g.commandQueue.ResumeX(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.registerFrameEventForXbox(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
g.framePipelineToken = _D3D12XBOX_FRAME_PIPELINE_TOKEN_NULL
|
g.framePipelineToken = _D3D12XBOX_FRAME_PIPELINE_TOKEN_NULL
|
||||||
if err := g.device.WaitFrameEventX(_D3D12XBOX_FRAME_EVENT_ORIGIN, windows.INFINITE, nil, _D3D12XBOX_WAIT_FRAME_EVENT_FLAG_NONE, &g.framePipelineToken); err != nil {
|
if err := g.device.WaitFrameEventX(_D3D12XBOX_FRAME_EVENT_ORIGIN, windows.INFINITE, nil, _D3D12XBOX_WAIT_FRAME_EVENT_FLAG_NONE, &g.framePipelineToken); err != nil {
|
||||||
return err
|
return err
|
||||||
|
Loading…
Reference in New Issue
Block a user