ebiten/internal/graphicsdriver/directx/d3d_windows.go

181 lines
4.9 KiB
Go

// Copyright 2023 The Ebitengine Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package directx
import (
"fmt"
"runtime"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// Reference:
// * https://github.com/wine-mirror/wine/blob/master/include/d3dcommon.idl
type _D3DCOMPILE uint32
const (
_D3DCOMPILE_OPTIMIZATION_LEVEL3 _D3DCOMPILE = (1 << 15)
)
type _D3D_DRIVER_TYPE int32
const (
_D3D_DRIVER_TYPE_UNKNOWN _D3D_DRIVER_TYPE = iota
_D3D_DRIVER_TYPE_HARDWARE
_D3D_DRIVER_TYPE_REFERENCE
_D3D_DRIVER_TYPE_NULL
_D3D_DRIVER_TYPE_SOFTWARE
_D3D_DRIVER_TYPE_WARP
)
type _D3D_FEATURE_LEVEL int32
const (
_D3D_FEATURE_LEVEL_9_1 _D3D_FEATURE_LEVEL = 0x9100
_D3D_FEATURE_LEVEL_9_2 _D3D_FEATURE_LEVEL = 0x9200
_D3D_FEATURE_LEVEL_9_3 _D3D_FEATURE_LEVEL = 0x9300
_D3D_FEATURE_LEVEL_10_0 _D3D_FEATURE_LEVEL = 0xa000
_D3D_FEATURE_LEVEL_10_1 _D3D_FEATURE_LEVEL = 0xa100
_D3D_FEATURE_LEVEL_11_0 _D3D_FEATURE_LEVEL = 0xb000
_D3D_FEATURE_LEVEL_11_1 _D3D_FEATURE_LEVEL = 0xb100
_D3D_FEATURE_LEVEL_12_0 _D3D_FEATURE_LEVEL = 0xc000
_D3D_FEATURE_LEVEL_12_1 _D3D_FEATURE_LEVEL = 0xc100
_D3D_FEATURE_LEVEL_12_2 _D3D_FEATURE_LEVEL = 0xc200
)
type _D3D_PRIMITIVE_TOPOLOGY int32
const (
_D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST _D3D_PRIMITIVE_TOPOLOGY = 4
)
type _D3D_ROOT_SIGNATURE_VERSION int32
const (
_D3D_ROOT_SIGNATURE_VERSION_1_0 _D3D_ROOT_SIGNATURE_VERSION = 0x1
)
var (
procD3DCompile *windows.LazyProc
)
func init() {
var d3dcompiler *windows.LazyDLL
// Enumerate possible DLL names for d3dcompiler_*.dll.
// https://walbourn.github.io/hlsl-fxc-and-d3dcompile/
for v := 47; v >= 33; v-- {
dll := windows.NewLazySystemDLL(fmt.Sprintf("d3dcompiler_%d.dll", v))
if err := dll.Load(); err != nil {
continue
}
d3dcompiler = dll
break
}
if d3dcompiler == nil {
return
}
procD3DCompile = d3dcompiler.NewProc("D3DCompile")
}
func isD3DCompilerDLLAvailable() bool {
return procD3DCompile != nil
}
func _D3DCompile(srcData []byte, sourceName string, pDefines []_D3D_SHADER_MACRO, pInclude unsafe.Pointer, entryPoint string, target string, flags1 uint32, flags2 uint32) (*_ID3DBlob, error) {
if !isD3DCompilerDLLAvailable() {
return nil, fmt.Errorf("directx: d3dcompiler_*.dll is missing in this environment")
}
// TODO: Define _ID3DInclude for pInclude, but is it possible in Go?
var defs unsafe.Pointer
if len(pDefines) > 0 {
defs = unsafe.Pointer(&pDefines[0])
}
sourceNameBytes := append([]byte(sourceName), 0)
entryPointBytes := append([]byte(entryPoint), 0)
targetBytes := append([]byte(target), 0)
var code *_ID3DBlob
var errorMsgs *_ID3DBlob
r, _, _ := procD3DCompile.Call(
uintptr(unsafe.Pointer(&srcData[0])), uintptr(len(srcData)), uintptr(unsafe.Pointer(&sourceNameBytes[0])),
uintptr(defs), uintptr(unsafe.Pointer(pInclude)), uintptr(unsafe.Pointer(&entryPointBytes[0])),
uintptr(unsafe.Pointer(&targetBytes[0])), uintptr(flags1), uintptr(flags2),
uintptr(unsafe.Pointer(&code)), uintptr(unsafe.Pointer(&errorMsgs)))
runtime.KeepAlive(pDefines)
runtime.KeepAlive(pInclude)
runtime.KeepAlive(sourceNameBytes)
runtime.KeepAlive(entryPointBytes)
runtime.KeepAlive(targetBytes)
if uint32(r) != uint32(windows.S_OK) {
if errorMsgs != nil {
defer errorMsgs.Release()
return nil, fmt.Errorf("directx: D3DCompile failed: %s: %w", errorMsgs.String(), handleError(windows.Handle(uint32(r))))
}
return nil, fmt.Errorf("directx: D3DCompile failed: %w", handleError(windows.Handle(uint32(r))))
}
return code, nil
}
type _D3D_SHADER_MACRO struct {
Name *byte
Definition *byte
}
type _ID3DBlob struct {
vtbl *_ID3DBlob_Vtbl
}
type _ID3DBlob_Vtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
GetBufferPointer uintptr
GetBufferSize uintptr
}
func (i *_ID3DBlob) AddRef() uint32 {
r, _, _ := syscall.Syscall(i.vtbl.AddRef, 1, uintptr(unsafe.Pointer(i)), 0, 0)
return uint32(r)
}
func (i *_ID3DBlob) GetBufferPointer() unsafe.Pointer {
r, _, _ := syscall.Syscall(i.vtbl.GetBufferPointer, 1, uintptr(unsafe.Pointer(i)),
0, 0)
return unsafe.Pointer(r)
}
func (i *_ID3DBlob) GetBufferSize() uintptr {
r, _, _ := syscall.Syscall(i.vtbl.GetBufferSize, 1, uintptr(unsafe.Pointer(i)),
0, 0)
return r
}
func (i *_ID3DBlob) Release() uint32 {
r, _, _ := syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
return uint32(r)
}
func (i *_ID3DBlob) String() string {
return string(unsafe.Slice((*byte)(unsafe.Pointer(i.GetBufferPointer())), i.GetBufferSize()))
}