mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
internal/graphicsdriver/directx: refactoring: add graphicsInfra
This commit is contained in:
parent
0b46d2b799
commit
c9469a64ee
@ -546,11 +546,12 @@ type _IDXGISwapChain4_Vtbl struct {
|
|||||||
SetHDRMetaData uintptr
|
SetHDRMetaData uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *_IDXGISwapChain4) GetBuffer(buffer uint32) (*_ID3D12Resource, error) {
|
func (i *_IDXGISwapChain4) GetBuffer(buffer uint32, riid *windows.GUID) (unsafe.Pointer, error) {
|
||||||
var resource *_ID3D12Resource
|
var resource unsafe.Pointer
|
||||||
r, _, _ := syscall.Syscall6(i.vtbl.GetBuffer, 4, uintptr(unsafe.Pointer(i)),
|
r, _, _ := syscall.Syscall6(i.vtbl.GetBuffer, 4, uintptr(unsafe.Pointer(i)),
|
||||||
uintptr(buffer), uintptr(unsafe.Pointer(&_IID_ID3D12Resource)), uintptr(unsafe.Pointer(&resource)),
|
uintptr(buffer), uintptr(unsafe.Pointer(riid)), uintptr(unsafe.Pointer(&resource)),
|
||||||
0, 0)
|
0, 0)
|
||||||
|
runtime.KeepAlive(riid)
|
||||||
if uint32(r) != uint32(windows.S_OK) {
|
if uint32(r) != uint32(windows.S_OK) {
|
||||||
return nil, fmt.Errorf("directx: IDXGISwapChain4::GetBuffer failed: %w", handleError(windows.Handle(uint32(r))))
|
return nil, fmt.Errorf("directx: IDXGISwapChain4::GetBuffer failed: %w", handleError(windows.Handle(uint32(r))))
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"time"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
@ -30,8 +29,6 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir/hlsl"
|
"github.com/hajimehoshi/ebiten/v2/internal/shaderir/hlsl"
|
||||||
)
|
)
|
||||||
|
|
||||||
const frameCount = 2
|
|
||||||
|
|
||||||
type resourceWithSize struct {
|
type resourceWithSize struct {
|
||||||
value *_ID3D12Resource
|
value *_ID3D12Resource
|
||||||
sizeInBytes uint32
|
sizeInBytes uint32
|
||||||
@ -79,10 +76,7 @@ type graphics12 struct {
|
|||||||
vertices [frameCount][]*resourceWithSize
|
vertices [frameCount][]*resourceWithSize
|
||||||
indices [frameCount][]*resourceWithSize
|
indices [frameCount][]*resourceWithSize
|
||||||
|
|
||||||
allowTearing bool
|
graphicsInfra *graphicsInfra
|
||||||
|
|
||||||
factory *_IDXGIFactory4
|
|
||||||
swapChain *_IDXGISwapChain4
|
|
||||||
|
|
||||||
window windows.HWND
|
window windows.HWND
|
||||||
|
|
||||||
@ -104,12 +98,6 @@ type graphics12 struct {
|
|||||||
vsyncEnabled bool
|
vsyncEnabled bool
|
||||||
transparent bool
|
transparent bool
|
||||||
|
|
||||||
// occluded reports whether the screen is invisible or not.
|
|
||||||
occluded bool
|
|
||||||
|
|
||||||
// lastTime is the last time for rendering.
|
|
||||||
lastTime time.Time
|
|
||||||
|
|
||||||
newScreenWidth int
|
newScreenWidth int
|
||||||
newScreenHeight int
|
newScreenHeight int
|
||||||
|
|
||||||
@ -162,55 +150,41 @@ func (g *graphics12) initializeDesktop(useWARP bool, useDebugLayer bool, feature
|
|||||||
g.debug.EnableDebugLayer()
|
g.debug.EnableDebugLayer()
|
||||||
}
|
}
|
||||||
|
|
||||||
var flag uint32
|
gi, err := newGraphicsInfra(g.debug != nil)
|
||||||
if g.debug != nil {
|
|
||||||
flag = _DXGI_CREATE_FACTORY_DEBUG
|
|
||||||
}
|
|
||||||
f, err := _CreateDXGIFactory2(flag)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
g.factory = f
|
g.graphicsInfra = gi
|
||||||
defer func() {
|
defer func() {
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
g.factory.Release()
|
g.graphicsInfra.release()
|
||||||
g.factory = nil
|
g.graphicsInfra = nil
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
adapters, err := g.graphicsInfra.appendAdapters(nil, useWARP)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
for _, a := range adapters {
|
||||||
|
a.Release()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var adapter *_IDXGIAdapter1
|
var adapter *_IDXGIAdapter1
|
||||||
if useWARP {
|
if len(adapters) > 0 {
|
||||||
a, err := g.factory.EnumWarpAdapter()
|
if useWARP {
|
||||||
if err != nil {
|
adapter = adapters[0]
|
||||||
return err
|
} else {
|
||||||
}
|
for _, a := range adapters {
|
||||||
defer a.Release()
|
// Test D3D12CreateDevice without creating an actual device.
|
||||||
adapter = a
|
if _, err := _D3D12CreateDevice(unsafe.Pointer(a), featureLevel, &_IID_ID3D12Device, false); err != nil {
|
||||||
} else {
|
continue
|
||||||
for i := 0; ; i++ {
|
}
|
||||||
a, err := g.factory.EnumAdapters1(uint32(i))
|
adapter = a
|
||||||
if errors.Is(err, _DXGI_ERROR_NOT_FOUND) {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer a.Release()
|
|
||||||
|
|
||||||
desc, err := a.GetDesc1()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if desc.Flags&_DXGI_ADAPTER_FLAG_SOFTWARE != 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Test D3D12CreateDevice without creating an actual device.
|
|
||||||
if _, err := _D3D12CreateDevice(unsafe.Pointer(a), featureLevel, &_IID_ID3D12Device, false); err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
adapter = a
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,15 +198,6 @@ func (g *graphics12) initializeDesktop(useWARP bool, useDebugLayer bool, feature
|
|||||||
}
|
}
|
||||||
g.device = (*_ID3D12Device)(d)
|
g.device = (*_ID3D12Device)(d)
|
||||||
|
|
||||||
if f, err := g.factory.QueryInterface(&_IID_IDXGIFactory5); err == nil && f != nil {
|
|
||||||
factory := (*_IDXGIFactory5)(f)
|
|
||||||
defer factory.Release()
|
|
||||||
var allowTearing int32
|
|
||||||
if err := factory.CheckFeatureSupport(_DXGI_FEATURE_PRESENT_ALLOW_TEARING, unsafe.Pointer(&allowTearing), uint32(unsafe.Sizeof(allowTearing))); err == nil && allowTearing != 0 {
|
|
||||||
g.allowTearing = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := g.initializeMembers(g.frameIndex); err != nil {
|
if err := g.initializeMembers(g.frameIndex); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -495,21 +460,18 @@ func (g *graphics12) updateSwapChain(width, height int) error {
|
|||||||
return errors.New("directx: the window handle is not initialized yet")
|
return errors.New("directx: the window handle is not initialized yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.swapChain == nil {
|
if microsoftgdk.IsXbox() {
|
||||||
if microsoftgdk.IsXbox() {
|
if err := g.initSwapChainXbox(width, height); err != nil {
|
||||||
if err := g.initSwapChainXbox(width, height); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := g.initSwapChainDesktop(width, height); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if microsoftgdk.IsXbox() {
|
if !g.graphicsInfra.isSwapChainInited() {
|
||||||
return errors.New("directx: resizing should never happen on Xbox")
|
if err := g.initSwapChainDesktop(width, height); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
g.newScreenWidth = width
|
g.newScreenWidth = width
|
||||||
@ -518,45 +480,8 @@ func (g *graphics12) updateSwapChain(width, height int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *graphics12) initSwapChainDesktop(width, height int) (ferr error) {
|
func (g *graphics12) initSwapChainDesktop(width, height int) error {
|
||||||
// Create a swap chain.
|
g.graphicsInfra.initSwapChain(width, height, unsafe.Pointer(g.commandQueue), g.window)
|
||||||
//
|
|
||||||
// DXGI_ALPHA_MODE_PREMULTIPLIED doesn't work with a HWND well.
|
|
||||||
//
|
|
||||||
// IDXGIFactory::CreateSwapChain: Alpha blended swapchains must be created with CreateSwapChainForComposition,
|
|
||||||
// or CreateSwapChainForCoreWindow with the DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER flag
|
|
||||||
desc := &_DXGI_SWAP_CHAIN_DESC1{
|
|
||||||
Width: uint32(width),
|
|
||||||
Height: uint32(height),
|
|
||||||
Format: _DXGI_FORMAT_B8G8R8A8_UNORM,
|
|
||||||
BufferUsage: _DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
|
||||||
BufferCount: frameCount,
|
|
||||||
SwapEffect: _DXGI_SWAP_EFFECT_FLIP_DISCARD,
|
|
||||||
SampleDesc: _DXGI_SAMPLE_DESC{
|
|
||||||
Count: 1,
|
|
||||||
Quality: 0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if g.allowTearing {
|
|
||||||
desc.Flags |= uint32(_DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING)
|
|
||||||
}
|
|
||||||
s, err := g.factory.CreateSwapChainForHwnd(unsafe.Pointer(g.commandQueue), g.window, desc, nil, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s.As(&g.swapChain)
|
|
||||||
defer func() {
|
|
||||||
if ferr != nil {
|
|
||||||
g.swapChain.Release()
|
|
||||||
g.swapChain = nil
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// MakeWindowAssociation should be called after swap chain creation.
|
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgifactory-makewindowassociation
|
|
||||||
if err := g.factory.MakeWindowAssociation(g.window, _DXGI_MWA_NO_WINDOW_CHANGES|_DXGI_MWA_NO_ALT_ENTER); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Get the current buffer index?
|
// TODO: Get the current buffer index?
|
||||||
|
|
||||||
@ -564,7 +489,7 @@ func (g *graphics12) initSwapChainDesktop(width, height int) (ferr error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
g.frameIndex = int(g.swapChain.GetCurrentBackBufferIndex())
|
g.frameIndex = g.graphicsInfra.currentBackBufferIndex()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -636,11 +561,7 @@ func (g *graphics12) resizeSwapChainDesktop(width, height int) error {
|
|||||||
r.Release()
|
r.Release()
|
||||||
}
|
}
|
||||||
|
|
||||||
var flag uint32
|
if err := g.graphicsInfra.resizeSwapChain(width, height); err != nil {
|
||||||
if g.allowTearing {
|
|
||||||
flag |= uint32(_DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING)
|
|
||||||
}
|
|
||||||
if err := g.swapChain.ResizeBuffers(frameCount, uint32(width), uint32(height), _DXGI_FORMAT_B8G8R8A8_UNORM, flag); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -658,11 +579,11 @@ func (g *graphics12) createRenderTargetViewsDesktop() (ferr error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for i := 0; i < frameCount; i++ {
|
for i := 0; i < frameCount; i++ {
|
||||||
r, err := g.swapChain.GetBuffer(uint32(i))
|
r, err := g.graphicsInfra.getBuffer(uint32(i), &_IID_ID3D12Resource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
g.renderTargets[i] = r
|
g.renderTargets[i] = (*_ID3D12Resource)(r)
|
||||||
defer func(i int) {
|
defer func(i int) {
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
g.renderTargets[i].Release()
|
g.renderTargets[i].Release()
|
||||||
@ -670,7 +591,7 @@ func (g *graphics12) createRenderTargetViewsDesktop() (ferr error) {
|
|||||||
}
|
}
|
||||||
}(i)
|
}(i)
|
||||||
|
|
||||||
g.device.CreateRenderTargetView(r, nil, h)
|
g.device.CreateRenderTargetView((*_ID3D12Resource)(r), nil, h)
|
||||||
h.Offset(1, g.rtvDescriptorSize)
|
h.Offset(1, g.rtvDescriptorSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -795,40 +716,7 @@ func (g *graphics12) End(present bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *graphics12) presentDesktop() error {
|
func (g *graphics12) presentDesktop() error {
|
||||||
if g.swapChain == nil {
|
return g.graphicsInfra.present(g.vsyncEnabled)
|
||||||
return fmt.Errorf("directx: the swap chain is not initialized yet at End")
|
|
||||||
}
|
|
||||||
|
|
||||||
var syncInterval uint32
|
|
||||||
var flags _DXGI_PRESENT
|
|
||||||
if g.occluded {
|
|
||||||
// The screen is not visible. Test whether we can resume.
|
|
||||||
flags |= _DXGI_PRESENT_TEST
|
|
||||||
} else {
|
|
||||||
// Do actual rendering only when the screen is visible.
|
|
||||||
if g.vsyncEnabled {
|
|
||||||
syncInterval = 1
|
|
||||||
} else if g.allowTearing {
|
|
||||||
flags |= _DXGI_PRESENT_ALLOW_TEARING
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
occluded, err := g.swapChain.Present(syncInterval, uint32(flags))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
g.occluded = occluded
|
|
||||||
|
|
||||||
// Reduce FPS when the screen is invisible.
|
|
||||||
now := time.Now()
|
|
||||||
if g.occluded {
|
|
||||||
if delta := 100*time.Millisecond - now.Sub(g.lastTime); delta > 0 {
|
|
||||||
time.Sleep(delta)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.lastTime = now
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *graphics12) presentXbox() error {
|
func (g *graphics12) presentXbox() error {
|
||||||
@ -849,7 +737,7 @@ func (g *graphics12) moveToNextFrame() error {
|
|||||||
if microsoftgdk.IsXbox() {
|
if microsoftgdk.IsXbox() {
|
||||||
g.frameIndex = (g.frameIndex + 1) % frameCount
|
g.frameIndex = (g.frameIndex + 1) % frameCount
|
||||||
} else {
|
} else {
|
||||||
g.frameIndex = int(g.swapChain.GetCurrentBackBufferIndex())
|
g.frameIndex = g.graphicsInfra.currentBackBufferIndex()
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.fence.GetCompletedValue() < g.fenceValues[g.frameIndex] {
|
if g.fence.GetCompletedValue() < g.fenceValues[g.frameIndex] {
|
||||||
|
@ -15,12 +15,21 @@
|
|||||||
package directx
|
package directx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const frameCount = 2
|
||||||
|
|
||||||
// NewGraphics creates an implementation of graphicsdriver.Graphics for DirectX.
|
// NewGraphics creates an implementation of graphicsdriver.Graphics for DirectX.
|
||||||
// The returned graphics value is nil iff the error is not nil.
|
// The returned graphics value is nil iff the error is not nil.
|
||||||
func NewGraphics() (graphicsdriver.Graphics, error) {
|
func NewGraphics() (graphicsdriver.Graphics, error) {
|
||||||
@ -68,3 +77,201 @@ func NewGraphics() (graphicsdriver.Graphics, error) {
|
|||||||
}
|
}
|
||||||
return g, nil
|
return g, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type graphicsInfra struct {
|
||||||
|
factory *_IDXGIFactory4
|
||||||
|
swapChain *_IDXGISwapChain4
|
||||||
|
|
||||||
|
allowTearing bool
|
||||||
|
|
||||||
|
// occluded reports whether the screen is invisible or not.
|
||||||
|
occluded bool
|
||||||
|
|
||||||
|
// lastTime is the last time for rendering.
|
||||||
|
lastTime time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGraphicsInfra(debug bool) (*graphicsInfra, error) {
|
||||||
|
var flag uint32
|
||||||
|
if debug {
|
||||||
|
flag = _DXGI_CREATE_FACTORY_DEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := _CreateDXGIFactory2(flag)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
g := &graphicsInfra{
|
||||||
|
factory: f,
|
||||||
|
}
|
||||||
|
runtime.SetFinalizer(g, (*graphicsInfra).release)
|
||||||
|
|
||||||
|
if f, err := g.factory.QueryInterface(&_IID_IDXGIFactory5); err == nil && f != nil {
|
||||||
|
factory := (*_IDXGIFactory5)(f)
|
||||||
|
defer factory.Release()
|
||||||
|
|
||||||
|
var allowTearing int32
|
||||||
|
if err := factory.CheckFeatureSupport(_DXGI_FEATURE_PRESENT_ALLOW_TEARING, unsafe.Pointer(&allowTearing), uint32(unsafe.Sizeof(allowTearing))); err == nil && allowTearing != 0 {
|
||||||
|
g.allowTearing = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return g, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *graphicsInfra) release() {
|
||||||
|
if g.factory != nil {
|
||||||
|
g.factory.Release()
|
||||||
|
g.factory = nil
|
||||||
|
}
|
||||||
|
if g.swapChain != nil {
|
||||||
|
g.swapChain.Release()
|
||||||
|
g.swapChain = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendAdapters appends found adapters to the given adapters.
|
||||||
|
// Releasing them is the caller's responsibility.
|
||||||
|
func (g *graphicsInfra) appendAdapters(adapters []*_IDXGIAdapter1, warp bool) ([]*_IDXGIAdapter1, error) {
|
||||||
|
if warp {
|
||||||
|
a, err := g.factory.EnumWarpAdapter()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
adapters = append(adapters, a)
|
||||||
|
return adapters, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := uint32(0); ; i++ {
|
||||||
|
a, err := g.factory.EnumAdapters1(i)
|
||||||
|
if errors.Is(err, _DXGI_ERROR_NOT_FOUND) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
desc, err := a.GetDesc1()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if desc.Flags&_DXGI_ADAPTER_FLAG_SOFTWARE != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
adapters = append(adapters, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *graphicsInfra) isSwapChainInited() bool {
|
||||||
|
return g.swapChain != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *graphicsInfra) initSwapChain(width, height int, device unsafe.Pointer, window windows.HWND) (ferr error) {
|
||||||
|
if g.swapChain != nil {
|
||||||
|
return fmt.Errorf("directx: swap chain must not be initialized at initSwapChain, but is already done")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a swap chain.
|
||||||
|
//
|
||||||
|
// DXGI_ALPHA_MODE_PREMULTIPLIED doesn't work with a HWND well.
|
||||||
|
//
|
||||||
|
// IDXGIFactory::CreateSwapChain: Alpha blended swapchains must be created with CreateSwapChainForComposition,
|
||||||
|
// or CreateSwapChainForCoreWindow with the DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER flag
|
||||||
|
desc := &_DXGI_SWAP_CHAIN_DESC1{
|
||||||
|
Width: uint32(width),
|
||||||
|
Height: uint32(height),
|
||||||
|
Format: _DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||||
|
BufferUsage: _DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
||||||
|
BufferCount: frameCount,
|
||||||
|
SwapEffect: _DXGI_SWAP_EFFECT_FLIP_DISCARD,
|
||||||
|
SampleDesc: _DXGI_SAMPLE_DESC{
|
||||||
|
Count: 1,
|
||||||
|
Quality: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if g.allowTearing {
|
||||||
|
desc.Flags |= uint32(_DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING)
|
||||||
|
}
|
||||||
|
s, err := g.factory.CreateSwapChainForHwnd(device, window, desc, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.As(&g.swapChain)
|
||||||
|
defer func() {
|
||||||
|
if ferr != nil {
|
||||||
|
g.release()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// MakeWindowAssociation should be called after swap chain creation.
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgifactory-makewindowassociation
|
||||||
|
if err := g.factory.MakeWindowAssociation(window, _DXGI_MWA_NO_WINDOW_CHANGES|_DXGI_MWA_NO_ALT_ENTER); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *graphicsInfra) resizeSwapChain(width, height int) error {
|
||||||
|
if g.swapChain == nil {
|
||||||
|
return fmt.Errorf("directx: swap chain must be initialized at resizeSwapChain, but is not")
|
||||||
|
}
|
||||||
|
|
||||||
|
var flag uint32
|
||||||
|
if g.allowTearing {
|
||||||
|
flag |= uint32(_DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING)
|
||||||
|
}
|
||||||
|
if err := g.swapChain.ResizeBuffers(frameCount, uint32(width), uint32(height), _DXGI_FORMAT_B8G8R8A8_UNORM, flag); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *graphicsInfra) currentBackBufferIndex() int {
|
||||||
|
return int(g.swapChain.GetCurrentBackBufferIndex())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *graphicsInfra) present(vsyncEnabled bool) error {
|
||||||
|
if g.swapChain == nil {
|
||||||
|
return fmt.Errorf("directx: swap chain must be initialized at present, but is not")
|
||||||
|
}
|
||||||
|
|
||||||
|
var syncInterval uint32
|
||||||
|
var flags _DXGI_PRESENT
|
||||||
|
if g.occluded {
|
||||||
|
// The screen is not visible. Test whether we can resume.
|
||||||
|
flags |= _DXGI_PRESENT_TEST
|
||||||
|
} else {
|
||||||
|
// Do actual rendering only when the screen is visible.
|
||||||
|
if vsyncEnabled {
|
||||||
|
syncInterval = 1
|
||||||
|
} else if g.allowTearing {
|
||||||
|
flags |= _DXGI_PRESENT_ALLOW_TEARING
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
occluded, err := g.swapChain.Present(syncInterval, uint32(flags))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g.occluded = occluded
|
||||||
|
|
||||||
|
// Reduce FPS when the screen is invisible.
|
||||||
|
now := time.Now()
|
||||||
|
if g.occluded {
|
||||||
|
if delta := 100*time.Millisecond - now.Sub(g.lastTime); delta > 0 {
|
||||||
|
time.Sleep(delta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.lastTime = now
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *graphicsInfra) getBuffer(buffer uint32, riid *windows.GUID) (unsafe.Pointer, error) {
|
||||||
|
return g.swapChain.GetBuffer(buffer, riid)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user