internal/graphicsdriver/directx: refactoring

This is a preparation for a DirectX 11 driver.

Updates #2613
This commit is contained in:
Hajime Hoshi 2023-03-27 14:14:22 +09:00
parent 4779bbc04d
commit c8a2e5dc71
7 changed files with 140 additions and 120 deletions

View File

@ -726,7 +726,7 @@ type _D3D12_ROOT_SIGNATURE_DESC struct {
}
type _D3D12_SHADER_BYTECODE struct {
pShaderBytecode uintptr
pShaderBytecode unsafe.Pointer
BytecodeLength uintptr
}
@ -1507,10 +1507,10 @@ func (i *_ID3D12Device) CreateRenderTargetView(pResource *_ID3D12Resource, pDesc
runtime.KeepAlive(pDesc)
}
func (i *_ID3D12Device) CreateRootSignature(nodeMask uint32, pBlobWithRootSignature uintptr, blobLengthInBytes uintptr) (*_ID3D12RootSignature, error) {
func (i *_ID3D12Device) CreateRootSignature(nodeMask uint32, pBlobWithRootSignature unsafe.Pointer, blobLengthInBytes uintptr) (*_ID3D12RootSignature, error) {
var signature *_ID3D12RootSignature
r, _, _ := syscall.Syscall6(i.vtbl.CreateRootSignature, 6, uintptr(unsafe.Pointer(i)),
uintptr(nodeMask), pBlobWithRootSignature, blobLengthInBytes,
uintptr(nodeMask), uintptr(pBlobWithRootSignature), blobLengthInBytes,
uintptr(unsafe.Pointer(&_IID_ID3D12RootSignature)), uintptr(unsafe.Pointer(&signature)))
if uint32(r) != uint32(windows.S_OK) {
return nil, fmt.Errorf("directx: ID3D12Device::CreateRootSignature failed: %w", handleError(windows.Handle(uint32(r))))

View File

@ -112,10 +112,10 @@ func (i *_ID3DBlob) AddRef() uint32 {
return uint32(r)
}
func (i *_ID3DBlob) GetBufferPointer() uintptr {
func (i *_ID3DBlob) GetBufferPointer() unsafe.Pointer {
r, _, _ := syscall.Syscall(i.vtbl.GetBufferPointer, 1, uintptr(unsafe.Pointer(i)),
0, 0)
return r
return unsafe.Pointer(r)
}
func (i *_ID3DBlob) GetBufferSize() uintptr {

View File

@ -17,7 +17,6 @@ package directx
import (
"errors"
"fmt"
"math"
"unsafe"
"golang.org/x/sys/windows"
@ -91,9 +90,9 @@ type graphics12 struct {
nextImageID graphicsdriver.ImageID
disposedImages [frameCount][]*image12
shaders map[graphicsdriver.ShaderID]*Shader
shaders map[graphicsdriver.ShaderID]*shader12
nextShaderID graphicsdriver.ShaderID
disposedShaders [frameCount][]*Shader
disposedShaders [frameCount][]*shader12
vsyncEnabled bool
transparent bool
@ -864,18 +863,6 @@ func (g *graphics12) SetTransparent(transparent bool) {
g.transparent = transparent
}
func pow2(x uint32) uint32 {
if x > (math.MaxUint32+1)/2 {
return math.MaxUint32
}
var p2 uint32 = 1
for p2 < x {
p2 *= 2
}
return p2
}
func (g *graphics12) SetVertices(vertices []float32, indices []uint16) (ferr error) {
// Create buffers if necessary.
vidx := len(g.vertices[g.frameIndex])
@ -884,7 +871,7 @@ func (g *graphics12) SetVertices(vertices []float32, indices []uint16) (ferr err
} else {
g.vertices[g.frameIndex] = append(g.vertices[g.frameIndex], nil)
}
vsize := pow2(uint32(len(vertices)) * uint32(unsafe.Sizeof(float32(0))))
vsize := pow2(uint32(len(vertices)) * uint32(unsafe.Sizeof(vertices[0])))
if g.vertices[g.frameIndex][vidx] != nil && g.vertices[g.frameIndex][vidx].sizeInBytes < vsize {
g.vertices[g.frameIndex][vidx].release()
g.vertices[g.frameIndex][vidx] = nil
@ -913,7 +900,7 @@ func (g *graphics12) SetVertices(vertices []float32, indices []uint16) (ferr err
} else {
g.indices[g.frameIndex] = append(g.indices[g.frameIndex], nil)
}
isize := pow2(uint32(len(indices)) * uint32(unsafe.Sizeof(uint16(0))))
isize := pow2(uint32(len(indices)) * uint32(unsafe.Sizeof(indices[0])))
if g.indices[g.frameIndex][iidx] != nil && g.indices[g.frameIndex][iidx].sizeInBytes < isize {
g.indices[g.frameIndex][iidx].release()
g.indices[g.frameIndex][iidx] = nil
@ -1031,9 +1018,9 @@ func (g *graphics12) removeImage(img *image12) {
g.disposedImages[g.frameIndex] = append(g.disposedImages[g.frameIndex], img)
}
func (g *graphics12) addShader(s *Shader) {
func (g *graphics12) addShader(s *shader12) {
if g.shaders == nil {
g.shaders = map[graphicsdriver.ShaderID]*Shader{}
g.shaders = map[graphicsdriver.ShaderID]*shader12{}
}
if _, ok := g.shaders[s.id]; ok {
panic(fmt.Sprintf("directx: shader ID %d was already registered", s.id))
@ -1041,7 +1028,7 @@ func (g *graphics12) addShader(s *Shader) {
g.shaders[s.id] = s
}
func (g *graphics12) removeShader(s *Shader) {
func (g *graphics12) removeShader(s *shader12) {
delete(g.shaders, s.id)
g.disposedShaders[g.frameIndex] = append(g.disposedShaders[g.frameIndex], s)
}
@ -1078,7 +1065,7 @@ func (g *graphics12) NewShader(program *shaderir.Program) (graphicsdriver.Shader
return nil, err
}
s := &Shader{
s := &shader12{
graphics: g,
id: g.genNextShaderID(),
uniformTypes: program.Uniforms,
@ -1138,7 +1125,7 @@ func (g *graphics12) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.
}
shader := g.shaders[shaderID]
adjustedUniforms := shader.adjustUniforms(uniforms)
adjustedUniforms := adjustUniforms(shader.uniformTypes, shader.uniformOffsets, uniforms)
w, h := dst.internalSize()
g.needFlushDrawCommandList = true

View File

@ -17,6 +17,7 @@ package directx
import (
"errors"
"fmt"
"math"
"os"
"runtime"
"strings"
@ -28,8 +29,28 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
)
type stencilMode int
const (
prepareStencil stencilMode = iota
drawWithStencil
noStencil
)
const frameCount = 2
func pow2(x uint32) uint32 {
if x > (math.MaxUint32+1)/2 {
return math.MaxUint32
}
var p2 uint32 = 1
for p2 < x {
p2 *= 2
}
return p2
}
// NewGraphics creates an implementation of graphicsdriver.Graphics for DirectX.
// The returned graphics value is nil iff the error is not nil.
func NewGraphics() (graphicsdriver.Graphics, error) {

View File

@ -23,7 +23,7 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
)
var inputElementDescs = []_D3D12_INPUT_ELEMENT_DESC{
var inputElementDescsForDX12 = []_D3D12_INPUT_ELEMENT_DESC{
{
SemanticName: &([]byte("POSITION\000"))[0],
SemanticIndex: 0,
@ -55,7 +55,7 @@ var inputElementDescs = []_D3D12_INPUT_ELEMENT_DESC{
const numDescriptorsPerFrame = 32
func blendFactorToBlend(f graphicsdriver.BlendFactor, alpha bool) _D3D12_BLEND {
func blendFactorToBlend12(f graphicsdriver.BlendFactor, alpha bool) _D3D12_BLEND {
// D3D12_RENDER_TARGET_BLEND_DESC's *BlendAlpha members don't allow *_COLOR values.
// See https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_render_target_blend_desc.
@ -99,7 +99,7 @@ func blendFactorToBlend(f graphicsdriver.BlendFactor, alpha bool) _D3D12_BLEND {
}
}
func blendOperationToBlendOp(o graphicsdriver.BlendOperation) _D3D12_BLEND_OP {
func blendOperationToBlendOp12(o graphicsdriver.BlendOperation) _D3D12_BLEND_OP {
switch o {
case graphicsdriver.BlendOperationAdd:
return _D3D12_BLEND_OP_ADD
@ -176,7 +176,7 @@ func (p *pipelineStates) initialize(device *_ID3D12Device) (ferr error) {
return nil
}
func (p *pipelineStates) drawTriangles(device *_ID3D12Device, commandList *_ID3D12GraphicsCommandList, frameIndex int, screen bool, srcs [graphics.ShaderImageCount]*image12, shader *Shader, dstRegions []graphicsdriver.DstRegion, uniforms []uint32, blend graphicsdriver.Blend, indexOffset int, evenOdd bool) error {
func (p *pipelineStates) drawTriangles(device *_ID3D12Device, commandList *_ID3D12GraphicsCommandList, frameIndex int, screen bool, srcs [graphics.ShaderImageCount]*image12, shader *shader12, dstRegions []graphicsdriver.DstRegion, uniforms []uint32, blend graphicsdriver.Blend, indexOffset int, evenOdd bool) error {
idx := len(p.constantBuffers[frameIndex])
if idx >= numDescriptorsPerFrame {
return fmt.Errorf("directx: too many constant buffers")
@ -479,12 +479,12 @@ func (p *pipelineStates) newPipelineState(device *_ID3D12Device, vsh, psh *_ID3D
{
BlendEnable: 1,
LogicOpEnable: 0,
SrcBlend: blendFactorToBlend(blend.BlendFactorSourceRGB, false),
DestBlend: blendFactorToBlend(blend.BlendFactorDestinationRGB, false),
BlendOp: blendOperationToBlendOp(blend.BlendOperationRGB),
SrcBlendAlpha: blendFactorToBlend(blend.BlendFactorSourceAlpha, true),
DestBlendAlpha: blendFactorToBlend(blend.BlendFactorDestinationAlpha, true),
BlendOpAlpha: blendOperationToBlendOp(blend.BlendOperationAlpha),
SrcBlend: blendFactorToBlend12(blend.BlendFactorSourceRGB, false),
DestBlend: blendFactorToBlend12(blend.BlendFactorDestinationRGB, false),
BlendOp: blendOperationToBlendOp12(blend.BlendOperationRGB),
SrcBlendAlpha: blendFactorToBlend12(blend.BlendFactorSourceAlpha, true),
DestBlendAlpha: blendFactorToBlend12(blend.BlendFactorDestinationAlpha, true),
BlendOpAlpha: blendOperationToBlendOp12(blend.BlendOperationAlpha),
LogicOp: _D3D12_LOGIC_OP_NOOP,
RenderTargetWriteMask: writeMask,
},
@ -506,8 +506,8 @@ func (p *pipelineStates) newPipelineState(device *_ID3D12Device, vsh, psh *_ID3D
},
DepthStencilState: depthStencilDesc,
InputLayout: _D3D12_INPUT_LAYOUT_DESC{
pInputElementDescs: &inputElementDescs[0],
NumElements: uint32(len(inputElementDescs)),
pInputElementDescs: &inputElementDescsForDX12[0],
NumElements: uint32(len(inputElementDescsForDX12)),
},
PrimitiveTopologyType: _D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
NumRenderTargets: 1,

View File

@ -0,0 +1,89 @@
// 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 (
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
)
type pipelineStateKey struct {
blend graphicsdriver.Blend
stencilMode stencilMode
screen bool
}
type shader12 struct {
graphics *graphics12
id graphicsdriver.ShaderID
uniformTypes []shaderir.Type
uniformOffsets []int
vertexShader *_ID3DBlob
pixelShader *_ID3DBlob
pipelineStates map[pipelineStateKey]*_ID3D12PipelineState
}
func (s *shader12) ID() graphicsdriver.ShaderID {
return s.id
}
func (s *shader12) Dispose() {
s.graphics.removeShader(s)
}
func (s *shader12) disposeImpl() {
for c, p := range s.pipelineStates {
p.Release()
delete(s.pipelineStates, c)
}
if s.pixelShader != nil {
s.pixelShader.Release()
s.pixelShader = nil
}
if s.vertexShader != nil {
count := s.vertexShader.Release()
if count == 0 {
for k, v := range vertexShaderCache {
if v == s.vertexShader {
delete(vertexShaderCache, k)
}
}
}
s.vertexShader = nil
}
}
func (s *shader12) pipelineState(blend graphicsdriver.Blend, stencilMode stencilMode, screen bool) (*_ID3D12PipelineState, error) {
key := pipelineStateKey{
blend: blend,
stencilMode: stencilMode,
screen: screen,
}
if state, ok := s.pipelineStates[key]; ok {
return state, nil
}
state, err := s.graphics.pipelineStates.newPipelineState(s.graphics.device, s.vertexShader, s.pixelShader, blend, stencilMode, screen)
if err != nil {
return nil, err
}
if s.pipelineStates == nil {
s.pipelineStates = map[pipelineStateKey]*_ID3D12PipelineState{}
}
s.pipelineStates[key] = state
return state, nil
}

View File

@ -20,34 +20,9 @@ import (
"golang.org/x/sync/errgroup"
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
)
type stencilMode int
const (
prepareStencil stencilMode = iota
drawWithStencil
noStencil
)
type pipelineStateKey struct {
blend graphicsdriver.Blend
stencilMode stencilMode
screen bool
}
type Shader struct {
graphics *graphics12
id graphicsdriver.ShaderID
uniformTypes []shaderir.Type
uniformOffsets []int
vertexShader *_ID3DBlob
pixelShader *_ID3DBlob
pipelineStates map[pipelineStateKey]*_ID3D12PipelineState
}
var vertexShaderCache = map[string]*_ID3DBlob{}
func compileShader(vs, ps string) (vsh, psh *_ID3DBlob, ferr error) {
@ -105,64 +80,12 @@ func compileShader(vs, ps string) (vsh, psh *_ID3DBlob, ferr error) {
return
}
func (s *Shader) ID() graphicsdriver.ShaderID {
return s.id
}
func (s *Shader) Dispose() {
s.graphics.removeShader(s)
}
func (s *Shader) disposeImpl() {
for c, p := range s.pipelineStates {
p.Release()
delete(s.pipelineStates, c)
}
if s.pixelShader != nil {
s.pixelShader.Release()
s.pixelShader = nil
}
if s.vertexShader != nil {
count := s.vertexShader.Release()
if count == 0 {
for k, v := range vertexShaderCache {
if v == s.vertexShader {
delete(vertexShaderCache, k)
}
}
}
s.vertexShader = nil
}
}
func (s *Shader) pipelineState(blend graphicsdriver.Blend, stencilMode stencilMode, screen bool) (*_ID3D12PipelineState, error) {
key := pipelineStateKey{
blend: blend,
stencilMode: stencilMode,
screen: screen,
}
if state, ok := s.pipelineStates[key]; ok {
return state, nil
}
state, err := s.graphics.pipelineStates.newPipelineState(s.graphics.device, s.vertexShader, s.pixelShader, blend, stencilMode, screen)
if err != nil {
return nil, err
}
if s.pipelineStates == nil {
s.pipelineStates = map[pipelineStateKey]*_ID3D12PipelineState{}
}
s.pipelineStates[key] = state
return state, nil
}
func (s *Shader) adjustUniforms(uniforms []uint32) []uint32 {
func adjustUniforms(uniformTypes []shaderir.Type, uniformOffsets []int, uniforms []uint32) []uint32 {
var fs []uint32
var idx int
for i, typ := range s.uniformTypes {
if len(fs) < s.uniformOffsets[i]/4 {
fs = append(fs, make([]uint32, s.uniformOffsets[i]/4-len(fs))...)
for i, typ := range uniformTypes {
if len(fs) < uniformOffsets[i]/4 {
fs = append(fs, make([]uint32, uniformOffsets[i]/4-len(fs))...)
}
n := typ.Uint32Count()