diff --git a/internal/graphicsdriver/directx/api_windows.go b/internal/graphicsdriver/directx/api_windows.go index 90e4694d6..f360432e0 100644 --- a/internal/graphicsdriver/directx/api_windows.go +++ b/internal/graphicsdriver/directx/api_windows.go @@ -41,7 +41,6 @@ func boolToUintptr(v bool) uintptr { // Reference: // * https://github.com/microsoft/DirectX-Headers // * https://github.com/microsoft/win32metadata -// * https://raw.githubusercontent.com/microsoft/win32metadata/master/generation/WinSDK/RecompiledIdlHeaders/um/d3d12.h const ( _D3D12_APPEND_ALIGNED_ELEMENT = 0xffffffff @@ -258,7 +257,8 @@ const ( type _D3D12_HEAP_FLAGS int32 const ( - _D3D12_HEAP_FLAG_NONE _D3D12_HEAP_FLAGS = 0 + _D3D12_HEAP_FLAG_NONE _D3D12_HEAP_FLAGS = 0 + _D3D12_HEAP_FLAG_ALLOW_DISPLAY _D3D12_HEAP_FLAGS = 0x8 ) type _D3D12_HEAP_TYPE int32 @@ -413,6 +413,10 @@ const ( type _D3D12_RTV_DIMENSION int32 +const ( + _D3D12_RTV_DIMENSION_TEXTURE2D _D3D12_RTV_DIMENSION = 4 +) + const ( _D3D12_SHADER_COMPONENT_MAPPING_MASK = 0x7 _D3D12_SHADER_COMPONENT_MAPPING_SHIFT = 3 @@ -502,6 +506,36 @@ const ( type _D3D12XBOX_CREATE_DEVICE_FLAGS int32 +type _D3D12XBOX_FRAME_EVENT_TYPE int32 + +const ( + _D3D12XBOX_FRAME_EVENT_ORIGIN _D3D12XBOX_FRAME_EVENT_TYPE = 0 +) + +type _D3D12XBOX_FRAME_INTERVAL_FLAGS int32 + +const ( + _D3D12XBOX_FRAME_INTERVAL_FLAG_NONE _D3D12XBOX_FRAME_INTERVAL_FLAGS = 0x0 +) + +type _D3D12XBOX_FRAME_PIPELINE_TOKEN uint64 + +const ( + _D3D12XBOX_FRAME_PIPELINE_TOKEN_NULL _D3D12XBOX_FRAME_PIPELINE_TOKEN = 0 +) + +type _D3D12XBOX_PRESENT_DESC_TITLE_PERFORMANCE_OVERLAY_FLAGS int32 + +type _D3D12XBOX_PRESENT_DESC_TYPE int32 + +type _D3D12XBOX_PRESENT_FLAGS int32 + +type _D3D12XBOX_PRESENT_PLANE_FLAGS int32 + +type _D3D12XBOX_PRESENT_PLANE_SCALE_FILTER int32 + +type _D3D12XBOX_PRESENT_PLANE_DESC_TYPE int32 + type _D3D12XBOX_PROCESS_DEBUG_FLAGS int32 const ( @@ -515,6 +549,22 @@ const ( _D3D12XBOX_PROCESS_DEBUG_FLAG_ENHANCED_VALIDATION _D3D12XBOX_PROCESS_DEBUG_FLAGS = 0x02000000 ) +type _D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAGS int32 + +const ( + _D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE _D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAGS = 0x0 +) + +type _D3D12XBOX_WAIT_FRAME_EVENT_FLAGS int32 + +const ( + _D3D12XBOX_WAIT_FRAME_EVENT_FLAG_NONE _D3D12XBOX_WAIT_FRAME_EVENT_FLAGS = 0x0 +) + +const ( + _D3D12XBOX_FRAME_INTERVAL_60_HZ = 16667 +) + type _DXGI_ALPHA_MODE uint32 const ( @@ -525,6 +575,8 @@ const ( _DXGI_ALPHA_MODE_FORCE_DWORD _DXGI_ALPHA_MODE = 0xffffffff ) +type _DXGI_COLOR_SPACE_TYPE int32 + type _DXGI_FORMAT int32 const ( @@ -580,6 +632,7 @@ var ( _IID_ID3D12RootSignature = windows.GUID{Data1: 0xc54a6b66, Data2: 0x72df, Data3: 0x4ee8, Data4: [...]byte{0x8b, 0xe5, 0xa9, 0x46, 0xa1, 0x42, 0x92, 0x14}} _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: 0x99cdbe06, Data2: 0xc52d, Data3: 0xa562, Data4: [...]byte{0x8d, 0x0a, 0xc4, 0x2f, 0xe3, 0x33, 0xf9, 0x47}} _IID_IDXGIFactory4 = windows.GUID{Data1: 0x1bc6ea02, Data2: 0xef36, Data3: 0x464f, Data4: [...]byte{0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a}} ) @@ -896,6 +949,62 @@ type _D3D12XBOX_CREATE_DEVICE_PARAMETERS struct { DisableAutomaticCommandSegmentChaining _BOOL } +type _D3D12XBOX_PRESENT_DESC_TITLE_PERFORMANCE_OVERLAY struct { + Flags _D3D12XBOX_PRESENT_DESC_TITLE_PERFORMANCE_OVERLAY_FLAGS + RenderResolutionWidth uint16 + RenderResolutionHeight uint16 + MaxResolutionWidth uint16 + MaxResolutionHeight uint16 +} + +type _D3D12XBOX_PRESENT_PARAMETERS struct { + ImmediateThresholdPercent float32 + ViewCount uint32 + ExtendedDescCount uint32 + pExtendedDescs *_D3D12XBOX_PRESENT_DESC + Flags _D3D12XBOX_PRESENT_FLAGS +} + +type _D3D12XBOX_PRESENT_DESC struct { + Type _D3D12XBOX_PRESENT_DESC_TYPE + TitlePerfOverlay _D3D12XBOX_PRESENT_DESC_TITLE_PERFORMANCE_OVERLAY +} + +type _D3D12XBOX_PRESENT_PLANE_DESC struct { + Type _D3D12XBOX_PRESENT_PLANE_DESC_TYPE +} + +type _D3D12XBOX_PRESENT_PLANE_PARAMETERS struct { + Token _D3D12XBOX_FRAME_PIPELINE_TOKEN + ResourceCount uint32 + ppResources **_ID3D12Resource + pSrcViewRects *_D3D12_RECT + pDestPlacementBase *_D3D12XBOX_VIEW_RECT + ColorSpace _DXGI_COLOR_SPACE_TYPE + ScaleFilter _D3D12XBOX_PRESENT_PLANE_SCALE_FILTER + ExtendedDescCount uint32 + pExtendedDescs *_D3D12XBOX_PRESENT_PLANE_DESC + Flags _D3D12XBOX_PRESENT_PLANE_FLAGS +} + +type _D3D12XBOX_SCHEDULE_FRAME_OBJECT_LIST struct { + Count uint32 + pObjects *windows.Handle +} + +type _D3D12XBOX_VIEW_RECT struct { + left float32 + top float32 + right float32 + bottom float32 +} + +type _D3D12XBOX_WAIT_FRAME_OBJECT_LIST struct { + Count uint32 + pObjects *windows.Handle + pSignaledObjectIndex *uint32 +} + var ( d3d12 = windows.NewLazySystemDLL("d3d12.dll") d3d12x = windows.NewLazySystemDLL(microsoftgdk.D3D12DLLName()) @@ -1169,7 +1278,23 @@ type _ID3D12CommandQueue_Vtbl struct { Wait uintptr GetTimestampFrequency uintptr GetClockCalibration uintptr - GetDesc uintptr + GetDesc uintptr // Is this another function for Xbox? + + // These members are for Xbox. + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr // Is this GetDesc for Xbox? + _ uintptr + _ uintptr + _ uintptr + PresentX uintptr + _ uintptr + _ uintptr } func (i *_ID3D12CommandQueue) ExecuteCommandLists(ppCommandLists []*_ID3D12GraphicsCommandList) { @@ -1178,6 +1303,16 @@ func (i *_ID3D12CommandQueue) ExecuteCommandLists(ppCommandLists []*_ID3D12Graph runtime.KeepAlive(ppCommandLists) } +func (i *_ID3D12CommandQueue) PresentX(planeCount uint32, pPlaneParameters *_D3D12XBOX_PRESENT_PLANE_PARAMETERS, pPresentParameters *_D3D12XBOX_PRESENT_PARAMETERS) error { + r, _, _ := syscall.Syscall6(i.vtbl.PresentX, 4, uintptr(unsafe.Pointer(i)), uintptr(planeCount), uintptr(unsafe.Pointer(pPlaneParameters)), uintptr(unsafe.Pointer(pPresentParameters)), 0, 0) + runtime.KeepAlive(pPlaneParameters) + runtime.KeepAlive(pPresentParameters) + if uint32(r) != uint32(windows.S_OK) { + return fmt.Errorf("directx: ID3D12CommandQueue::PresentX failed: HRESULT(%d)", uint32(r)) + } + return nil +} + func (i *_ID3D12CommandQueue) Signal(signal *_ID3D12Fence, value uint64) error { r, _, _ := syscall.Syscall(i.vtbl.Signal, 3, uintptr(unsafe.Pointer(i)), uintptr(unsafe.Pointer(signal)), uintptr(value)) @@ -1379,45 +1514,49 @@ type _ID3D12Device_Vtbl struct { GetAdapterLuid uintptr // These members are for Xbox. - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - CreateCommandList_Xbox uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr - _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + CreateCommandListX uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + SetFrameIntervalX uintptr + ScheduleFrameEventX uintptr + WaitFrameEventX uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr + _ uintptr } func (i *_ID3D12Device) CreateCommandAllocator(typ _D3D12_COMMAND_LIST_TYPE) (*_ID3D12CommandAllocator, error) { @@ -1446,7 +1585,7 @@ func (i *_ID3D12Device) CreateCommandList(nodeMask uint32, typ _D3D12_COMMAND_LI Member3: nodeMask, Member4: 0, } - r, _, _ = syscall.Syscall6(i.vtbl.CreateCommandList_Xbox, 6, + r, _, _ = syscall.Syscall6(i.vtbl.CreateCommandListX, 6, uintptr(unsafe.Pointer(i)), uintptr(unsafe.Pointer(&desc)), uintptr(unsafe.Pointer(pCommandAllocator)), uintptr(unsafe.Pointer(pInitialState)), uintptr(unsafe.Pointer(&_IID_ID3D12GraphicsCommandList)), uintptr(unsafe.Pointer(&commandList))) } else { @@ -1596,6 +1735,42 @@ func (i *_ID3D12Device) GetDeviceRemovedReason() error { return nil } +func (i *_ID3D12Device) ScheduleFrameEventX(typ _D3D12XBOX_FRAME_EVENT_TYPE, intervalOffsetInMicroseconds uint32, pAncillarySignalList *_D3D12XBOX_SCHEDULE_FRAME_OBJECT_LIST, flags _D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAGS) error { + r, _, _ := syscall.Syscall6(i.vtbl.ScheduleFrameEventX, 5, uintptr(unsafe.Pointer(i)), uintptr(typ), uintptr(intervalOffsetInMicroseconds), uintptr(unsafe.Pointer(pAncillarySignalList)), uintptr(flags), 0) + runtime.KeepAlive(pAncillarySignalList) + if uint32(r) != uint32(windows.S_OK) { + return fmt.Errorf("directx: ID3D12Device::ScheduleFrameEventX failed: HRESULT(%d)", uint32(r)) + } + return nil +} + +func (i *_ID3D12Device) SetFrameIntervalX(pOutputSyncTarget *_IDXGIOutput, lengthInMicroseconds uint32, periodInIntervals uint32, flags _D3D12XBOX_FRAME_INTERVAL_FLAGS) error { + r, _, _ := syscall.Syscall6(i.vtbl.SetFrameIntervalX, 5, uintptr(unsafe.Pointer(i)), uintptr(unsafe.Pointer(pOutputSyncTarget)), uintptr(lengthInMicroseconds), uintptr(periodInIntervals), uintptr(flags), 0) + runtime.KeepAlive(pOutputSyncTarget) + if uint32(r) != uint32(windows.S_OK) { + return fmt.Errorf("directx: ID3D12Device::SetFrameIntervalX failed: HRESULT(%d)", uint32(r)) + } + return nil +} + +func (i *_ID3D12Device) QueryInterface(riid *windows.GUID, ppvObject *unsafe.Pointer) error { + r, _, _ := syscall.Syscall(i.vtbl.QueryInterface, 3, uintptr(unsafe.Pointer(i)), uintptr(unsafe.Pointer(riid)), uintptr(unsafe.Pointer(ppvObject))) + if uint32(r) != uint32(windows.S_OK) { + return fmt.Errorf("directx: ID3D12Device::QueryInterface failed: HRESULT(%d)", uint32(r)) + } + return nil +} + +func (i *_ID3D12Device) WaitFrameEventX(typ _D3D12XBOX_FRAME_EVENT_TYPE, timeOutInMs uint32, pAncillaryWaitList *_D3D12XBOX_WAIT_FRAME_OBJECT_LIST, flags _D3D12XBOX_WAIT_FRAME_EVENT_FLAGS, pToken *_D3D12XBOX_FRAME_PIPELINE_TOKEN) error { + r, _, _ := syscall.Syscall6(i.vtbl.WaitFrameEventX, 6, uintptr(unsafe.Pointer(i)), uintptr(typ), uintptr(timeOutInMs), uintptr(unsafe.Pointer(pAncillaryWaitList)), uintptr(flags), uintptr(unsafe.Pointer(pToken))) + runtime.KeepAlive(pAncillaryWaitList) + runtime.KeepAlive(pToken) + if uint32(r) != uint32(windows.S_OK) { + return fmt.Errorf("directx: ID3D12Device::WaitFrameEventX failed: HRESULT(%d)", uint32(r)) + } + return nil +} + type _ID3D12Fence struct { vtbl *_ID3D12Fence_Vtbl } @@ -2065,6 +2240,37 @@ func (i *_ID3DBlob) String() string { return str } +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: HRESULT(%d)", uint32(r)) + } + return pOutput, nil +} + +func (i *_IDXGIAdapter) Release() { + syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0) +} + type _IDXGIAdapter1 struct { vtbl *_IDXGIAdapter1_Vtbl } @@ -2097,6 +2303,39 @@ func (i *_IDXGIAdapter1) GetDesc1() (*_DXGI_ADAPTER_DESC1, error) { 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: HRESULT(%d)", uint32(r)) + } + return adapter, nil +} + +func (i *_IDXGIDevice) Release() { + syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0) +} + type _IDXGIFactory4 struct { vtbl *_IDXGIFactory4_Vtbl } @@ -2218,6 +2457,10 @@ type _IDXGIOutput_Vtbl struct { GetFrameStatistics uintptr } +func (i *_IDXGIOutput) Release() { + syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0) +} + type _ID3D12RootSignature struct { vtbl *_ID3D12RootSignature_Vtbl } diff --git a/internal/graphicsdriver/directx/graphics_windows.go b/internal/graphicsdriver/directx/graphics_windows.go index d38062412..d068c7785 100644 --- a/internal/graphicsdriver/directx/graphics_windows.go +++ b/internal/graphicsdriver/directx/graphics_windows.go @@ -91,12 +91,13 @@ func init() { } type Graphics struct { - debug *_ID3D12Debug - device *_ID3D12Device - commandQueue *_ID3D12CommandQueue - rtvDescriptorHeap *_ID3D12DescriptorHeap - rtvDescriptorSize uint32 - renderTargets [frameCount]*_ID3D12Resource + debug *_ID3D12Debug + device *_ID3D12Device + commandQueue *_ID3D12CommandQueue + rtvDescriptorHeap *_ID3D12DescriptorHeap + rtvDescriptorSize uint32 + renderTargets [frameCount]*_ID3D12Resource + framePipelineToken _D3D12XBOX_FRAME_PIPELINE_TOKEN fence *_ID3D12Fence fenceValues [frameCount]uint64 @@ -128,6 +129,9 @@ type Graphics struct { frameIndex int + // frameStarted is true since Begin until End with present + frameStarted bool + images map[graphicsdriver.ImageID]*Image screenImage *Image nextImageID graphicsdriver.ImageID @@ -284,6 +288,31 @@ func (g *Graphics) initializeXbox(useWARP bool, useDebugLayer bool) (ferr error) return err } + var dxgiDevice *_IDXGIDevice + if err := g.device.QueryInterface(&_IID_IDXGIDevice, (*unsafe.Pointer)(unsafe.Pointer(dxgiDevice))); err != nil { + return err + } + defer dxgiDevice.Release() + + dxgiAdapter, err := dxgiDevice.GetAdapter() + if err != nil { + return err + } + defer dxgiAdapter.Release() + + dxgiOutput, err := dxgiAdapter.EnumOutputs(0) + if err != nil { + return err + } + defer dxgiOutput.Release() + + if err := g.device.SetFrameIntervalX(dxgiOutput, _D3D12XBOX_FRAME_INTERVAL_60_HZ, frameCount-1, _D3D12XBOX_FRAME_INTERVAL_FLAG_NONE); err != nil { + return err + } + if err := g.device.ScheduleFrameEventX(_D3D12XBOX_FRAME_EVENT_ORIGIN, 0, nil, _D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE); err != nil { + return err + } + return nil } @@ -456,19 +485,30 @@ func (g *Graphics) updateSwapChain(width, height int) error { } if g.swapChain == nil { - if err := g.initSwapChain(width, height); err != nil { - return err - } - } else { - if err := g.resizeSwapChain(width, height); err != nil { - return err + if microsoftgdk.IsXbox() { + if err := g.initSwapChainXbox(width, height); err != nil { + return err + } + } else { + if err := g.initSwapChainDesktop(width, height); err != nil { + return err + } } + return nil + } + + if microsoftgdk.IsXbox() { + return errors.New("directx: resizing should never happen on Xbox") + } + + if err := g.resizeSwapChainDesktop(width, height); err != nil { + return err } return nil } -func (g *Graphics) initSwapChain(width, height int) (ferr error) { +func (g *Graphics) initSwapChainDesktop(width, height int) (ferr error) { // Create a swap chain. // // DXGI_ALPHA_MODE_PREMULTIPLIED doesn't work with a HWND well. @@ -506,7 +546,7 @@ func (g *Graphics) initSwapChain(width, height int) (ferr error) { // TODO: Get the current buffer index? - if err := g.createRenderTargetViews(); err != nil { + if err := g.createRenderTargetViewsDesktop(); err != nil { return err } @@ -515,7 +555,59 @@ func (g *Graphics) initSwapChain(width, height int) (ferr error) { return nil } -func (g *Graphics) resizeSwapChain(width, height int) error { +func (g *Graphics) initSwapChainXbox(width, height int) (ferr error) { + h, err := g.rtvDescriptorHeap.GetCPUDescriptorHandleForHeapStart() + if err != nil { + return err + } + + for i := 0; i < frameCount; i++ { + r, err := g.device.CreateCommittedResource(&_D3D12_HEAP_PROPERTIES{ + Type: _D3D12_HEAP_TYPE_DEFAULT, + CPUPageProperty: _D3D12_CPU_PAGE_PROPERTY_UNKNOWN, + MemoryPoolPreference: _D3D12_MEMORY_POOL_UNKNOWN, + CreationNodeMask: 1, + VisibleNodeMask: 1, + }, _D3D12_HEAP_FLAG_ALLOW_DISPLAY, &_D3D12_RESOURCE_DESC{ + Dimension: _D3D12_RESOURCE_DIMENSION_TEXTURE2D, + Alignment: 0, + Width: uint64(width), + Height: uint32(height), + DepthOrArraySize: 1, + MipLevels: 1, // Use a single mipmap level + Format: _DXGI_FORMAT_B8G8R8A8_UNORM, + SampleDesc: _DXGI_SAMPLE_DESC{ + Count: 1, + Quality: 0, + }, + Layout: _D3D12_TEXTURE_LAYOUT_UNKNOWN, + Flags: _D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, + }, _D3D12_RESOURCE_STATE_PRESENT, &_D3D12_CLEAR_VALUE{ + Format: _DXGI_FORMAT_B8G8R8A8_UNORM, + }) + if err != nil { + return err + } + + g.renderTargets[i] = r + defer func(i int) { + if ferr != nil { + g.renderTargets[i].Release() + g.renderTargets[i] = nil + } + }(i) + + g.device.CreateRenderTargetView(r, &_D3D12_RENDER_TARGET_VIEW_DESC{ + Format: _DXGI_FORMAT_B8G8R8A8_UNORM, + ViewDimension: _D3D12_RTV_DIMENSION_TEXTURE2D, + }, h) + h.Offset(1, g.rtvDescriptorSize) + } + + return nil +} + +func (g *Graphics) resizeSwapChainDesktop(width, height int) error { if err := g.flushCommandList(g.copyCommandList); err != nil { return err } @@ -549,7 +641,7 @@ func (g *Graphics) resizeSwapChain(width, height int) error { return err } - if err := g.createRenderTargetViews(); err != nil { + if err := g.createRenderTargetViewsDesktop(); err != nil { return err } @@ -566,7 +658,7 @@ func (g *Graphics) resizeSwapChain(width, height int) error { return nil } -func (g *Graphics) createRenderTargetViews() (ferr error) { +func (g *Graphics) createRenderTargetViewsDesktop() (ferr error) { // Create frame resources. h, err := g.rtvDescriptorHeap.GetCPUDescriptorHandleForHeapStart() if err != nil { @@ -598,6 +690,14 @@ func (g *Graphics) SetWindow(window uintptr) { } func (g *Graphics) Begin() error { + if microsoftgdk.IsXbox() && !g.frameStarted { + 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 + } + } + g.frameStarted = true + if err := g.drawCommandList.Reset(g.drawCommandAllocators[g.frameIndex], nil); err != nil { return err } @@ -640,16 +740,14 @@ func (g *Graphics) End(present bool) error { g.pipelineStates.resetConstantBuffers(g.frameIndex) if present { - if g.swapChain == nil { - return fmt.Errorf("directx: the swap chain is not initialized yet at End") - } - - var syncInterval uint32 - if g.vsyncEnabled { - syncInterval = 1 - } - if err := g.swapChain.Present(syncInterval, 0); err != nil { - return err + if microsoftgdk.IsXbox() { + if err := g.presentXbox(); err != nil { + return err + } + } else { + if err := g.presentDesktop(); err != nil { + return err + } } if err := g.moveToNextFrame(); err != nil { @@ -661,7 +759,35 @@ func (g *Graphics) End(present bool) error { if err := g.resetCommandAllocators(g.frameIndex); err != nil { return err } + + g.frameStarted = false } + + return nil +} + +func (g *Graphics) presentDesktop() error { + if g.swapChain == nil { + return fmt.Errorf("directx: the swap chain is not initialized yet at End") + } + + var syncInterval uint32 + if g.vsyncEnabled { + syncInterval = 1 + } + if err := g.swapChain.Present(syncInterval, 0); err != nil { + return err + } + + return nil +} + +func (g *Graphics) presentXbox() error { + g.commandQueue.PresentX(1, &_D3D12XBOX_PRESENT_PLANE_PARAMETERS{ + Token: g.framePipelineToken, + ResourceCount: 1, + ppResources: &g.renderTargets[g.frameIndex], + }, nil) return nil }