mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +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
|
||||
}
|
||||
|
||||
type _PAPPSTATE_CHANGE_ROUTINE func(quiesced bool, context unsafe.Pointer) uintptr
|
||||
|
||||
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")
|
||||
d3d12x = windows.NewLazySystemDLL(microsoftgdk.D3D12DLLName())
|
||||
d3dcompiler = windows.NewLazySystemDLL("d3dcompiler_47.dll")
|
||||
dxgi = windows.NewLazySystemDLL("dxgi.dll")
|
||||
|
||||
procRegisterAppStateChangeNotification = appnotify.NewProc("RegisterAppStateChangeNotification")
|
||||
|
||||
procD3D12CreateDevice = d3d12.NewProc("D3D12CreateDevice")
|
||||
procD3D12GetDebugInterface = d3d12.NewProc("D3D12GetDebugInterface")
|
||||
procD3D12SerializeRootSignature = d3d12.NewProc("D3D12SerializeRootSignature")
|
||||
@ -1115,6 +1121,16 @@ func _D3DCompile(srcData []byte, sourceName string, pDefines []_D3D_SHADER_MACRO
|
||||
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) {
|
||||
var factory *_IDXGIFactory4
|
||||
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.
|
||||
_ uintptr
|
||||
_ uintptr
|
||||
_ uintptr
|
||||
_ uintptr
|
||||
SuspendX uintptr
|
||||
ResumeX uintptr
|
||||
_ uintptr
|
||||
_ uintptr
|
||||
_ uintptr
|
||||
@ -1326,6 +1342,18 @@ func (i *_ID3D12CommandQueue) PresentX(planeCount uint32, pPlaneParameters *_D3D
|
||||
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 {
|
||||
var r uintptr
|
||||
if is64bit {
|
||||
@ -1342,9 +1370,11 @@ func (i *_ID3D12CommandQueue) Signal(signal *_ID3D12Fence, value uint64) error {
|
||||
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) SuspendX(flags uint32) error {
|
||||
if r, _, _ := syscall.Syscall(i.vtbl.SuspendX, 2, uintptr(unsafe.Pointer(i)), uintptr(flags), 0); uint32(r) != uint32(windows.S_OK) {
|
||||
return fmt.Errorf("directx: ID3D12CommandQueue::SuspendX failed: %w", handleError(windows.Handle(uint32(r))))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type _ID3D12Debug struct {
|
||||
|
@ -150,6 +150,10 @@ type Graphics struct {
|
||||
newScreenWidth int
|
||||
newScreenHeight int
|
||||
|
||||
suspendingCh chan struct{}
|
||||
suspendedCh chan struct{}
|
||||
resumeCh chan struct{}
|
||||
|
||||
pipelineStates
|
||||
}
|
||||
|
||||
@ -341,11 +345,35 @@ func (g *Graphics) initializeXbox(useWARP bool, useDebugLayer bool) (ferr error)
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
dxgiDevice := (*_IDXGIDevice)(dd)
|
||||
dxgiDevice := (*_IDXGIDevice)(d)
|
||||
defer dxgiDevice.Release()
|
||||
|
||||
dxgiAdapter, err := dxgiDevice.GetAdapter()
|
||||
@ -727,6 +755,22 @@ func (g *Graphics) SetWindow(window uintptr) {
|
||||
|
||||
func (g *Graphics) Begin() error {
|
||||
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
|
||||
if err := g.device.WaitFrameEventX(_D3D12XBOX_FRAME_EVENT_ORIGIN, windows.INFINITE, nil, _D3D12XBOX_WAIT_FRAME_EVENT_FLAG_NONE, &g.framePipelineToken); err != nil {
|
||||
return err
|
||||
|
Loading…
Reference in New Issue
Block a user