internal/graphicsdriver/directx: bug fix: use an associated IDXGIFactory

In DirectX 11, if a device and a factory are independently created,
some functions like MakeWindowAssociation doe't work well.

This change fixes the issue by getting a factory from a device and
using it.

Closes #2661
This commit is contained in:
Hajime Hoshi 2023-05-01 19:17:04 +09:00
parent b32258ab8c
commit d16b591a35
5 changed files with 63 additions and 22 deletions

View File

@ -821,6 +821,16 @@ func (i *_ID3D11Device) CreateVertexShader(pShaderBytecode unsafe.Pointer, bytec
return vertexShader, nil
}
func (i *_ID3D11Device) 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: ID3D11Device::QueryInterface failed: %w", handleError(windows.Handle(uint32(r))))
}
return v, nil
}
type _ID3D11DeviceContext struct {
vtbl *_ID3D11DeviceContext_Vtbl
}

View File

@ -190,6 +190,16 @@ func (i *_IDXGIAdapter) EnumOutputs(output uint32) (*_IDXGIOutput, error) {
return pOutput, nil
}
func (i *_IDXGIAdapter) GetParent(riid *windows.GUID) (unsafe.Pointer, error) {
var v unsafe.Pointer
r, _, _ := syscall.Syscall(i.vtbl.GetParent, 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: IDXGIAdapter::GetParent failed: %w", handleError(windows.Handle(uint32(r))))
}
return v, nil
}
func (i *_IDXGIAdapter) Release() uint32 {
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
return uint32(r)

View File

@ -154,18 +154,6 @@ func newGraphics11(useWARP bool, useDebugLayer bool) (gr11 *graphics11, ferr err
vsyncEnabled: true,
}
gi, err := newGraphicsInfra()
if err != nil {
return nil, err
}
g.graphicsInfra = gi
defer func() {
if ferr != nil {
g.graphicsInfra.release()
g.graphicsInfra = nil
}
}()
driverType := _D3D_DRIVER_TYPE_HARDWARE
if useWARP {
driverType = _D3D_DRIVER_TYPE_WARP
@ -186,14 +174,47 @@ func newGraphics11(useWARP bool, useDebugLayer bool) (gr11 *graphics11, ferr err
// Apparently, adapter must be nil if the driver type is not unknown. This is not documented explicitly.
// https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-d3d11createdevice
d, f, ctx, err := _D3D11CreateDevice(nil, driverType, 0, uint32(flags), featureLevels, true, true)
d, fl, ctx, err := _D3D11CreateDevice(nil, driverType, 0, uint32(flags), featureLevels, true, true)
if err != nil {
return nil, err
}
g.device = (*_ID3D11Device)(d)
g.featureLevel = f
g.featureLevel = fl
g.deviceContext = (*_ID3D11DeviceContext)(ctx)
// Get IDXGIFactory from the current device and use it, instead of CreateDXGIFactory.
// Or, MakeWindowAssociation doesn't work well (#2661).
dd, err := g.device.QueryInterface(&_IID_IDXGIDevice)
if err != nil {
return nil, err
}
dxgiDevice := (*_IDXGIDevice)(dd)
defer dxgiDevice.Release()
dxgiAdapter, err := dxgiDevice.GetAdapter()
if err != nil {
return nil, err
}
defer dxgiAdapter.Release()
df, err := dxgiAdapter.GetParent(&_IID_IDXGIFactory)
if err != nil {
return nil, err
}
dxgiFactory := (*_IDXGIFactory)(df)
gi, err := newGraphicsInfra(dxgiFactory)
if err != nil {
return nil, err
}
g.graphicsInfra = gi
defer func() {
if ferr != nil {
g.graphicsInfra.release()
g.graphicsInfra = nil
}
}()
g.deviceContext.IASetPrimitiveTopology(_D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST)
// Set the rasterizer state.

View File

@ -148,7 +148,11 @@ func (g *graphics12) initializeDesktop(useWARP bool, useDebugLayer bool, feature
g.debug.EnableDebugLayer()
}
gi, err := newGraphicsInfra()
f, err := _CreateDXGIFactory()
if err != nil {
return err
}
gi, err := newGraphicsInfra(f)
if err != nil {
return err
}

View File

@ -159,14 +159,10 @@ type graphicsInfra struct {
bufferCount int
}
func newGraphicsInfra() (*graphicsInfra, error) {
f, err := _CreateDXGIFactory()
if err != nil {
return nil, err
}
// newGraphicsInfra takes the ownership of the given factory.
func newGraphicsInfra(factory *_IDXGIFactory) (*graphicsInfra, error) {
g := &graphicsInfra{
factory: f,
factory: factory,
}
runtime.SetFinalizer(g, (*graphicsInfra).release)