mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 18:58:54 +01:00
internal/graphicsdriver/directx: implement DirectX 11 driver
Updates #2613
This commit is contained in:
parent
c8a2e5dc71
commit
78d76945ad
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@ -140,11 +140,13 @@ jobs:
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
go test -shuffle=on -v ./...
|
||||
env EBITENGINE_DIRECTX=version=12 go test -shuffle=on -v ./...
|
||||
|
||||
- name: go test (Windows 386)
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
env GOARCH=386 go test -shuffle=on -v ./...
|
||||
env GOARCH=386 EBITENGINE_DIRECTX=version=12 go test -shuffle=on -v ./...
|
||||
|
||||
- name: go test (Wasm)
|
||||
run: |
|
||||
|
7
doc.go
7
doc.go
@ -78,8 +78,13 @@
|
||||
// `EBITENGINE_DIRECTX` environment variable specifies various parameters for DirectX.
|
||||
// You can specify multiple values separated by a comma. The default value is empty (i.e. no parameters).
|
||||
//
|
||||
// "warp": Use WARP (i.e. software rendering).
|
||||
// "debug": Use a debug layer.
|
||||
// "warp": Use WARP (i.e. software rendering).
|
||||
// "version=11": Use DirectX 11 (default).
|
||||
// "version=12": Use DirectX 12.
|
||||
//
|
||||
// The options "version=..." are exclusive and if multiples are specified, the lastly specified value is adopted.
|
||||
// On Xbox, the version options are ignored and DirectX 12 is always adopted.
|
||||
//
|
||||
// `EBITENGINE_DIRECTX_FEATURE_LEVEL` environment variable specifies DirectX feature level.
|
||||
// The possible values are "11_0", "11_1", "12_0", "12_1", and "12_2".
|
||||
|
1338
internal/graphicsdriver/directx/d3d11_windows.go
Normal file
1338
internal/graphicsdriver/directx/d3d11_windows.go
Normal file
File diff suppressed because it is too large
Load Diff
@ -23,15 +23,34 @@ import (
|
||||
"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
|
||||
|
671
internal/graphicsdriver/directx/graphics11_windows.go
Normal file
671
internal/graphicsdriver/directx/graphics11_windows.go
Normal file
@ -0,0 +1,671 @@
|
||||
// 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"
|
||||
"math"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir/hlsl"
|
||||
)
|
||||
|
||||
var inputElementDescsForDX11 = []_D3D11_INPUT_ELEMENT_DESC{
|
||||
{
|
||||
SemanticName: &([]byte("POSITION\000"))[0],
|
||||
SemanticIndex: 0,
|
||||
Format: _DXGI_FORMAT_R32G32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D11_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D11_INPUT_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
},
|
||||
{
|
||||
SemanticName: &([]byte("TEXCOORD\000"))[0],
|
||||
SemanticIndex: 0,
|
||||
Format: _DXGI_FORMAT_R32G32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D11_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D11_INPUT_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
},
|
||||
{
|
||||
SemanticName: &([]byte("COLOR\000"))[0],
|
||||
SemanticIndex: 0,
|
||||
Format: _DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||||
InputSlot: 0,
|
||||
AlignedByteOffset: _D3D11_APPEND_ALIGNED_ELEMENT,
|
||||
InputSlotClass: _D3D11_INPUT_PER_VERTEX_DATA,
|
||||
InstanceDataStepRate: 0,
|
||||
},
|
||||
}
|
||||
|
||||
func blendFactorToBlend11(f graphicsdriver.BlendFactor, alpha bool) _D3D11_BLEND {
|
||||
switch f {
|
||||
case graphicsdriver.BlendFactorZero:
|
||||
return _D3D11_BLEND_ZERO
|
||||
case graphicsdriver.BlendFactorOne:
|
||||
return _D3D11_BLEND_ONE
|
||||
case graphicsdriver.BlendFactorSourceColor:
|
||||
if alpha {
|
||||
return _D3D11_BLEND_SRC_ALPHA
|
||||
}
|
||||
return _D3D11_BLEND_SRC_COLOR
|
||||
case graphicsdriver.BlendFactorOneMinusSourceColor:
|
||||
if alpha {
|
||||
return _D3D11_BLEND_INV_SRC_ALPHA
|
||||
}
|
||||
return _D3D11_BLEND_INV_SRC_COLOR
|
||||
case graphicsdriver.BlendFactorSourceAlpha:
|
||||
return _D3D11_BLEND_SRC_ALPHA
|
||||
case graphicsdriver.BlendFactorOneMinusSourceAlpha:
|
||||
return _D3D11_BLEND_INV_SRC_ALPHA
|
||||
case graphicsdriver.BlendFactorDestinationColor:
|
||||
if alpha {
|
||||
return _D3D11_BLEND_DEST_ALPHA
|
||||
}
|
||||
return _D3D11_BLEND_DEST_COLOR
|
||||
case graphicsdriver.BlendFactorOneMinusDestinationColor:
|
||||
if alpha {
|
||||
return _D3D11_BLEND_INV_DEST_ALPHA
|
||||
}
|
||||
return _D3D11_BLEND_INV_DEST_COLOR
|
||||
case graphicsdriver.BlendFactorDestinationAlpha:
|
||||
return _D3D11_BLEND_DEST_ALPHA
|
||||
case graphicsdriver.BlendFactorOneMinusDestinationAlpha:
|
||||
return _D3D11_BLEND_INV_DEST_ALPHA
|
||||
case graphicsdriver.BlendFactorSourceAlphaSaturated:
|
||||
return _D3D11_BLEND_SRC_ALPHA_SAT
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: invalid blend factor: %d", f))
|
||||
}
|
||||
}
|
||||
|
||||
func blendOperationToBlendOp11(o graphicsdriver.BlendOperation) _D3D11_BLEND_OP {
|
||||
switch o {
|
||||
case graphicsdriver.BlendOperationAdd:
|
||||
return _D3D11_BLEND_OP_ADD
|
||||
case graphicsdriver.BlendOperationSubtract:
|
||||
return _D3D11_BLEND_OP_SUBTRACT
|
||||
case graphicsdriver.BlendOperationReverseSubtract:
|
||||
return _D3D11_BLEND_OP_REV_SUBTRACT
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: invalid blend operation: %d", o))
|
||||
}
|
||||
}
|
||||
|
||||
type blendStateKey struct {
|
||||
blend graphicsdriver.Blend
|
||||
writeMask uint8
|
||||
}
|
||||
|
||||
type graphics11 struct {
|
||||
graphicsInfra *graphicsInfra
|
||||
|
||||
featureLevel _D3D_FEATURE_LEVEL
|
||||
|
||||
device *_ID3D11Device
|
||||
deviceContext *_ID3D11DeviceContext
|
||||
|
||||
images map[graphicsdriver.ImageID]*image11
|
||||
screenImage *image11
|
||||
nextImageID graphicsdriver.ImageID
|
||||
|
||||
shaders map[graphicsdriver.ShaderID]*shader11
|
||||
nextShaderID graphicsdriver.ShaderID
|
||||
|
||||
vertexBuffer *_ID3D11Buffer
|
||||
vertexBufferSizeInBytes uint32
|
||||
|
||||
indexBuffer *_ID3D11Buffer
|
||||
indexBufferSizeInBytes uint32
|
||||
|
||||
rasterizerState *_ID3D11RasterizerState
|
||||
samplerState *_ID3D11SamplerState
|
||||
blendStates map[blendStateKey]*_ID3D11BlendState
|
||||
depthStencilStates map[stencilMode]*_ID3D11DepthStencilState
|
||||
|
||||
vsyncEnabled bool
|
||||
window windows.HWND
|
||||
}
|
||||
|
||||
func newGraphics11(useWARP bool, useDebugLayer bool) (gr11 *graphics11, ferr error) {
|
||||
g := &graphics11{
|
||||
vsyncEnabled: true,
|
||||
}
|
||||
|
||||
gi, err := newGraphicsInfra(useDebugLayer)
|
||||
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
|
||||
}
|
||||
|
||||
var flags _D3D11_CREATE_DEVICE_FLAG
|
||||
if useDebugLayer {
|
||||
flags |= _D3D11_CREATE_DEVICE_DEBUG
|
||||
}
|
||||
|
||||
// Avoid _D3D_FEATURE_LEVEL_11_1 as DirectX 11.0 doesn't recgonize this.
|
||||
// Avoid _D3D_FEATURE_LEVEL_9_* for some shaders features (#1431).
|
||||
featureLevels := []_D3D_FEATURE_LEVEL{
|
||||
_D3D_FEATURE_LEVEL_11_0,
|
||||
_D3D_FEATURE_LEVEL_10_1,
|
||||
_D3D_FEATURE_LEVEL_10_0,
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.device = (*_ID3D11Device)(d)
|
||||
g.featureLevel = f
|
||||
g.deviceContext = (*_ID3D11DeviceContext)(ctx)
|
||||
|
||||
g.deviceContext.IASetPrimitiveTopology(_D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST)
|
||||
|
||||
// Set the rasterizer state.
|
||||
if g.rasterizerState == nil {
|
||||
rs, err := g.device.CreateRasterizerState(&_D3D11_RASTERIZER_DESC{
|
||||
FillMode: _D3D11_FILL_SOLID,
|
||||
CullMode: _D3D11_CULL_NONE,
|
||||
FrontCounterClockwise: 0,
|
||||
DepthBias: 0,
|
||||
DepthBiasClamp: 0,
|
||||
SlopeScaledDepthBias: 0,
|
||||
DepthClipEnable: 0,
|
||||
ScissorEnable: 1,
|
||||
MultisampleEnable: 0,
|
||||
AntialiasedLineEnable: 0,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.rasterizerState = rs
|
||||
}
|
||||
g.deviceContext.RSSetState(g.rasterizerState)
|
||||
|
||||
// Set the sampler state.
|
||||
if g.samplerState == nil {
|
||||
s, err := g.device.CreateSamplerState(&_D3D11_SAMPLER_DESC{
|
||||
Filter: _D3D11_FILTER_MIN_MAG_MIP_POINT,
|
||||
AddressU: _D3D11_TEXTURE_ADDRESS_WRAP,
|
||||
AddressV: _D3D11_TEXTURE_ADDRESS_WRAP,
|
||||
AddressW: _D3D11_TEXTURE_ADDRESS_WRAP,
|
||||
ComparisonFunc: _D3D11_COMPARISON_NEVER,
|
||||
MinLOD: -math.MaxFloat32,
|
||||
MaxLOD: math.MaxFloat32,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g.samplerState = s
|
||||
}
|
||||
g.deviceContext.PSSetSamplers(0, []*_ID3D11SamplerState{g.samplerState})
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (g *graphics11) Initialize() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *graphics11) Begin() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *graphics11) End(present bool) error {
|
||||
if !present {
|
||||
return nil
|
||||
}
|
||||
if err := g.graphicsInfra.present(g.vsyncEnabled); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *graphics11) SetWindow(window uintptr) {
|
||||
g.window = windows.HWND(window)
|
||||
// TODO: need to update the swap chain?
|
||||
}
|
||||
|
||||
func (g *graphics11) SetTransparent(transparent bool) {
|
||||
// TODO: Implement this?
|
||||
}
|
||||
|
||||
func (g *graphics11) SetVertices(vertices []float32, indices []uint16) error {
|
||||
if size := pow2(uint32(len(vertices)) * uint32(unsafe.Sizeof(vertices[0]))); g.vertexBufferSizeInBytes < size {
|
||||
if g.vertexBuffer != nil {
|
||||
g.vertexBuffer.Release()
|
||||
g.vertexBuffer = nil
|
||||
}
|
||||
b, err := g.device.CreateBuffer(&_D3D11_BUFFER_DESC{
|
||||
ByteWidth: size,
|
||||
Usage: _D3D11_USAGE_DYNAMIC,
|
||||
BindFlags: uint32(_D3D11_BIND_VERTEX_BUFFER),
|
||||
CPUAccessFlags: uint32(_D3D11_CPU_ACCESS_WRITE),
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.vertexBuffer = b
|
||||
g.vertexBufferSizeInBytes = size
|
||||
g.deviceContext.IASetVertexBuffers(0, []*_ID3D11Buffer{g.vertexBuffer},
|
||||
[]uint32{graphics.VertexFloatCount * uint32(unsafe.Sizeof(vertices[0]))}, []uint32{0})
|
||||
}
|
||||
if size := pow2(uint32(len(indices)) * uint32(unsafe.Sizeof(indices[0]))); g.indexBufferSizeInBytes < size {
|
||||
if g.indexBuffer != nil {
|
||||
g.indexBuffer.Release()
|
||||
g.indexBuffer = nil
|
||||
}
|
||||
b, err := g.device.CreateBuffer(&_D3D11_BUFFER_DESC{
|
||||
ByteWidth: size,
|
||||
Usage: _D3D11_USAGE_DYNAMIC,
|
||||
BindFlags: uint32(_D3D11_BIND_INDEX_BUFFER),
|
||||
CPUAccessFlags: uint32(_D3D11_CPU_ACCESS_WRITE),
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.indexBuffer = b
|
||||
g.indexBufferSizeInBytes = size
|
||||
g.deviceContext.IASetIndexBuffer(g.indexBuffer, _DXGI_FORMAT_R16_UINT, 0)
|
||||
}
|
||||
|
||||
// Copy the vertices data.
|
||||
{
|
||||
var mapped _D3D11_MAPPED_SUBRESOURCE
|
||||
if err := g.deviceContext.Map(unsafe.Pointer(g.vertexBuffer), 0, _D3D11_MAP_WRITE_DISCARD, 0, &mapped); err != nil {
|
||||
return err
|
||||
}
|
||||
copy(unsafe.Slice((*float32)(mapped.pData), len(vertices)), vertices)
|
||||
g.deviceContext.Unmap(unsafe.Pointer(g.vertexBuffer), 0)
|
||||
}
|
||||
|
||||
// Copy the indices data.
|
||||
{
|
||||
var mapped _D3D11_MAPPED_SUBRESOURCE
|
||||
if err := g.deviceContext.Map(unsafe.Pointer(g.indexBuffer), 0, _D3D11_MAP_WRITE_DISCARD, 0, &mapped); err != nil {
|
||||
return err
|
||||
}
|
||||
copy(unsafe.Slice((*uint16)(mapped.pData), len(indices)), indices)
|
||||
g.deviceContext.Unmap(unsafe.Pointer(g.indexBuffer), 0)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *graphics11) NewImage(width, height int) (graphicsdriver.Image, error) {
|
||||
t, err := g.device.CreateTexture2D(&_D3D11_TEXTURE2D_DESC{
|
||||
Width: uint32(graphics.InternalImageSize(width)),
|
||||
Height: uint32(graphics.InternalImageSize(height)),
|
||||
MipLevels: 1, // 0 doesn't work when shrinking the image.
|
||||
ArraySize: 1,
|
||||
Format: _DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
SampleDesc: _DXGI_SAMPLE_DESC{
|
||||
Count: 1,
|
||||
Quality: 0,
|
||||
},
|
||||
Usage: _D3D11_USAGE_DEFAULT,
|
||||
BindFlags: uint32(_D3D11_BIND_SHADER_RESOURCE | _D3D11_BIND_RENDER_TARGET),
|
||||
CPUAccessFlags: 0,
|
||||
MiscFlags: 0,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
i := &image11{
|
||||
graphics: g,
|
||||
id: g.genNextImageID(),
|
||||
width: width,
|
||||
height: height,
|
||||
texture: t,
|
||||
}
|
||||
g.addImage(i)
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (g *graphics11) NewScreenFramebufferImage(width, height int) (graphicsdriver.Image, error) {
|
||||
if g.graphicsInfra.isSwapChainInited() {
|
||||
if g.screenImage != nil {
|
||||
g.screenImage.Dispose()
|
||||
g.screenImage = nil
|
||||
}
|
||||
if err := g.graphicsInfra.resizeSwapChain(width, height); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if err := g.graphicsInfra.initSwapChain(width, height, unsafe.Pointer(g.device), g.window); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if g.screenImage != nil {
|
||||
g.screenImage.Dispose()
|
||||
g.screenImage = nil
|
||||
}
|
||||
|
||||
t, err := g.graphicsInfra.getBuffer(0, &_IID_ID3D11Texture2D)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
i := &image11{
|
||||
graphics: g,
|
||||
id: g.genNextImageID(),
|
||||
width: width,
|
||||
height: height,
|
||||
screen: true,
|
||||
texture: (*_ID3D11Texture2D)(t),
|
||||
}
|
||||
g.addImage(i)
|
||||
g.screenImage = i
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (g *graphics11) addImage(img *image11) {
|
||||
if g.images == nil {
|
||||
g.images = map[graphicsdriver.ImageID]*image11{}
|
||||
}
|
||||
if _, ok := g.images[img.id]; ok {
|
||||
panic(fmt.Sprintf("directx: image ID %d was already registered", img.id))
|
||||
}
|
||||
g.images[img.id] = img
|
||||
}
|
||||
|
||||
func (g *graphics11) removeImage(image *image11) {
|
||||
delete(g.images, image.id)
|
||||
}
|
||||
|
||||
func (g *graphics11) SetVsyncEnabled(enabled bool) {
|
||||
g.vsyncEnabled = enabled
|
||||
}
|
||||
|
||||
func (g *graphics11) NeedsRestoring() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (g *graphics11) NeedsClearingScreen() bool {
|
||||
// TODO: Confirm this is really true.
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *graphics11) IsGL() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (g *graphics11) IsDirectX() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *graphics11) MaxImageSize() int {
|
||||
switch g.featureLevel {
|
||||
case _D3D_FEATURE_LEVEL_10_0:
|
||||
return 8192
|
||||
case _D3D_FEATURE_LEVEL_10_1:
|
||||
return 8192
|
||||
case _D3D_FEATURE_LEVEL_11_0:
|
||||
return 16384
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: invalid feature level: 0x%x", g.featureLevel))
|
||||
}
|
||||
}
|
||||
|
||||
func (g *graphics11) NewShader(program *shaderir.Program) (graphicsdriver.Shader, error) {
|
||||
vs, ps, offsets := hlsl.Compile(program)
|
||||
vsh, psh, err := compileShader(vs, ps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := &shader11{
|
||||
graphics: g,
|
||||
id: g.genNextShaderID(),
|
||||
uniformTypes: program.Uniforms,
|
||||
uniformOffsets: offsets,
|
||||
vertexShaderBlob: vsh,
|
||||
pixelShaderBlob: psh,
|
||||
}
|
||||
g.addShader(s)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (g *graphics11) addShader(s *shader11) {
|
||||
if g.shaders == nil {
|
||||
g.shaders = map[graphicsdriver.ShaderID]*shader11{}
|
||||
}
|
||||
if _, ok := g.shaders[s.id]; ok {
|
||||
panic(fmt.Sprintf("directx: shader ID %d was already registered", s.id))
|
||||
}
|
||||
g.shaders[s.id] = s
|
||||
}
|
||||
|
||||
func (g *graphics11) removeShader(s *shader11) {
|
||||
s.disposeImpl()
|
||||
delete(g.shaders, s.id)
|
||||
}
|
||||
|
||||
func (g *graphics11) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, evenOdd bool) error {
|
||||
// Remove bound textures first. This is needed to avoid warnings on the debugger.
|
||||
g.deviceContext.OMSetRenderTargets([]*_ID3D11RenderTargetView{nil}, nil)
|
||||
srvs := [graphics.ShaderImageCount]*_ID3D11ShaderResourceView{}
|
||||
g.deviceContext.PSSetShaderResources(0, srvs[:])
|
||||
|
||||
dst := g.images[dstID]
|
||||
var srcs [graphics.ShaderImageCount]*image11
|
||||
for i, id := range srcIDs {
|
||||
img := g.images[id]
|
||||
if img == nil {
|
||||
continue
|
||||
}
|
||||
srcs[i] = img
|
||||
}
|
||||
|
||||
w, h := dst.internalSize()
|
||||
g.deviceContext.RSSetViewports([]_D3D11_VIEWPORT{
|
||||
{
|
||||
TopLeftX: 0,
|
||||
TopLeftY: 0,
|
||||
Width: float32(w),
|
||||
Height: float32(h),
|
||||
MinDepth: 0,
|
||||
MaxDepth: 1,
|
||||
},
|
||||
})
|
||||
|
||||
if err := dst.setAsRenderTarget(evenOdd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set the shader parameters.
|
||||
shader := g.shaders[shaderID]
|
||||
if err := shader.use(uniforms, srcs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !evenOdd {
|
||||
bs, err := g.blendState(blend, noStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.deviceContext.OMSetBlendState(bs, nil, 0xffffffff)
|
||||
|
||||
dss, err := g.depthStencilState(noStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.deviceContext.OMSetDepthStencilState(dss, 0)
|
||||
}
|
||||
|
||||
for _, dstRegion := range dstRegions {
|
||||
g.deviceContext.RSSetScissorRects([]_D3D11_RECT{
|
||||
{
|
||||
left: int32(dstRegion.Region.X),
|
||||
top: int32(dstRegion.Region.Y),
|
||||
right: int32(dstRegion.Region.X + dstRegion.Region.Width),
|
||||
bottom: int32(dstRegion.Region.Y + dstRegion.Region.Height),
|
||||
},
|
||||
})
|
||||
|
||||
if evenOdd {
|
||||
bs, err := g.blendState(blend, prepareStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.deviceContext.OMSetBlendState(bs, nil, 0xffffffff)
|
||||
dss, err := g.depthStencilState(prepareStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.deviceContext.OMSetDepthStencilState(dss, 0)
|
||||
g.deviceContext.DrawIndexed(uint32(dstRegion.IndexCount), uint32(indexOffset), 0)
|
||||
|
||||
bs, err = g.blendState(blend, drawWithStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.deviceContext.OMSetBlendState(bs, nil, 0xffffffff)
|
||||
dss, err = g.depthStencilState(drawWithStencil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.deviceContext.OMSetDepthStencilState(dss, 0)
|
||||
g.deviceContext.DrawIndexed(uint32(dstRegion.IndexCount), uint32(indexOffset), 0)
|
||||
} else {
|
||||
g.deviceContext.DrawIndexed(uint32(dstRegion.IndexCount), uint32(indexOffset), 0)
|
||||
}
|
||||
|
||||
indexOffset += dstRegion.IndexCount
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *graphics11) genNextImageID() graphicsdriver.ImageID {
|
||||
g.nextImageID++
|
||||
return g.nextImageID
|
||||
}
|
||||
|
||||
func (g *graphics11) genNextShaderID() graphicsdriver.ShaderID {
|
||||
g.nextShaderID++
|
||||
return g.nextShaderID
|
||||
}
|
||||
|
||||
func (g *graphics11) blendState(blend graphicsdriver.Blend, stencilMode stencilMode) (*_ID3D11BlendState, error) {
|
||||
writeMask := uint8(_D3D11_COLOR_WRITE_ENABLE_ALL)
|
||||
if stencilMode == prepareStencil {
|
||||
writeMask = 0
|
||||
}
|
||||
|
||||
key := blendStateKey{
|
||||
blend: blend,
|
||||
writeMask: writeMask,
|
||||
}
|
||||
if bs, ok := g.blendStates[key]; ok {
|
||||
return bs, nil
|
||||
}
|
||||
|
||||
bs, err := g.device.CreateBlendState(&_D3D11_BLEND_DESC{
|
||||
AlphaToCoverageEnable: 0,
|
||||
IndependentBlendEnable: 0,
|
||||
RenderTarget: [8]_D3D11_RENDER_TARGET_BLEND_DESC{
|
||||
{
|
||||
BlendEnable: 1,
|
||||
SrcBlend: blendFactorToBlend11(blend.BlendFactorSourceRGB, false),
|
||||
DestBlend: blendFactorToBlend11(blend.BlendFactorDestinationRGB, false),
|
||||
BlendOp: blendOperationToBlendOp11(blend.BlendOperationRGB),
|
||||
SrcBlendAlpha: blendFactorToBlend11(blend.BlendFactorSourceAlpha, true),
|
||||
DestBlendAlpha: blendFactorToBlend11(blend.BlendFactorDestinationAlpha, true),
|
||||
BlendOpAlpha: blendOperationToBlendOp11(blend.BlendOperationAlpha),
|
||||
RenderTargetWriteMask: writeMask,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if g.blendStates == nil {
|
||||
g.blendStates = map[blendStateKey]*_ID3D11BlendState{}
|
||||
}
|
||||
g.blendStates[key] = bs
|
||||
return bs, nil
|
||||
}
|
||||
|
||||
func (g *graphics11) depthStencilState(mode stencilMode) (*_ID3D11DepthStencilState, error) {
|
||||
if s, ok := g.depthStencilStates[mode]; ok {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
desc := &_D3D11_DEPTH_STENCIL_DESC{
|
||||
DepthEnable: 0,
|
||||
DepthWriteMask: _D3D11_DEPTH_WRITE_MASK_ALL,
|
||||
DepthFunc: _D3D11_COMPARISON_LESS,
|
||||
StencilEnable: 0,
|
||||
StencilReadMask: _D3D11_DEFAULT_STENCIL_READ_MASK,
|
||||
StencilWriteMask: _D3D11_DEFAULT_STENCIL_WRITE_MASK,
|
||||
FrontFace: _D3D11_DEPTH_STENCILOP_DESC{
|
||||
StencilFailOp: _D3D11_STENCIL_OP_KEEP,
|
||||
StencilDepthFailOp: _D3D11_STENCIL_OP_KEEP,
|
||||
StencilPassOp: _D3D11_STENCIL_OP_KEEP,
|
||||
StencilFunc: _D3D11_COMPARISON_ALWAYS,
|
||||
},
|
||||
BackFace: _D3D11_DEPTH_STENCILOP_DESC{
|
||||
StencilFailOp: _D3D11_STENCIL_OP_KEEP,
|
||||
StencilDepthFailOp: _D3D11_STENCIL_OP_KEEP,
|
||||
StencilPassOp: _D3D11_STENCIL_OP_KEEP,
|
||||
StencilFunc: _D3D11_COMPARISON_ALWAYS,
|
||||
},
|
||||
}
|
||||
switch mode {
|
||||
case prepareStencil:
|
||||
desc.StencilEnable = 1
|
||||
desc.FrontFace.StencilPassOp = _D3D11_STENCIL_OP_INVERT
|
||||
desc.BackFace.StencilPassOp = _D3D11_STENCIL_OP_INVERT
|
||||
case drawWithStencil:
|
||||
desc.StencilEnable = 1
|
||||
desc.FrontFace.StencilFunc = _D3D11_COMPARISON_NOT_EQUAL
|
||||
desc.BackFace.StencilFunc = _D3D11_COMPARISON_NOT_EQUAL
|
||||
}
|
||||
|
||||
s, err := g.device.CreateDepthStencilState(desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if g.depthStencilStates == nil {
|
||||
g.depthStencilStates = map[stencilMode]*_ID3D11DepthStencilState{}
|
||||
}
|
||||
g.depthStencilStates[mode] = s
|
||||
return s, nil
|
||||
}
|
@ -27,6 +27,7 @@ import (
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk"
|
||||
)
|
||||
|
||||
type stencilMode int
|
||||
@ -54,10 +55,10 @@ func pow2(x uint32) uint32 {
|
||||
// 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) {
|
||||
var (
|
||||
useWARP bool
|
||||
useDebugLayer bool
|
||||
)
|
||||
var useWARP bool
|
||||
var useDebugLayer bool
|
||||
version := 11
|
||||
|
||||
env := os.Getenv("EBITENGINE_DIRECTX")
|
||||
if env == "" {
|
||||
// For backward compatibility, read the EBITEN_ version.
|
||||
@ -70,10 +71,27 @@ func NewGraphics() (graphicsdriver.Graphics, error) {
|
||||
useWARP = true
|
||||
case "debug":
|
||||
useDebugLayer = true
|
||||
case "version=11":
|
||||
version = 11
|
||||
case "version=12":
|
||||
version = 12
|
||||
}
|
||||
}
|
||||
|
||||
// Specify the level 11 by default.
|
||||
// On Xbox, only DirectX 12 is available.
|
||||
if microsoftgdk.IsXbox() {
|
||||
version = 12
|
||||
}
|
||||
|
||||
switch version {
|
||||
case 11:
|
||||
g, err := newGraphics11(useWARP, useDebugLayer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return g, nil
|
||||
case 12:
|
||||
// Specify the feature level 11 by default.
|
||||
// Some old cards don't work well with the default feature level (#2447, #2486).
|
||||
var featureLevel _D3D_FEATURE_LEVEL = _D3D_FEATURE_LEVEL_11_0
|
||||
if env := os.Getenv("EBITENGINE_DIRECTX_FEATURE_LEVEL"); env != "" {
|
||||
@ -91,12 +109,14 @@ func NewGraphics() (graphicsdriver.Graphics, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Implement a new graphics for DirectX 11 (#2613).
|
||||
g, err := newGraphics12(useWARP, useDebugLayer, featureLevel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return g, nil
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: unexpected DirectX version: %d", version))
|
||||
}
|
||||
}
|
||||
|
||||
type graphicsInfra struct {
|
||||
|
200
internal/graphicsdriver/directx/image11_windows.go
Normal file
200
internal/graphicsdriver/directx/image11_windows.go
Normal file
@ -0,0 +1,200 @@
|
||||
// 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"
|
||||
"unsafe"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
)
|
||||
|
||||
type image11 struct {
|
||||
graphics *graphics11
|
||||
id graphicsdriver.ImageID
|
||||
width int
|
||||
height int
|
||||
screen bool
|
||||
|
||||
texture *_ID3D11Texture2D
|
||||
stencil *_ID3D11Texture2D
|
||||
renderTargetView *_ID3D11RenderTargetView
|
||||
stencilView *_ID3D11DepthStencilView
|
||||
shaderResourceView *_ID3D11ShaderResourceView
|
||||
}
|
||||
|
||||
func (i *image11) internalSize() (int, int) {
|
||||
if i.screen {
|
||||
return i.width, i.height
|
||||
}
|
||||
return graphics.InternalImageSize(i.width), graphics.InternalImageSize(i.height)
|
||||
}
|
||||
|
||||
func (i *image11) ID() graphicsdriver.ImageID {
|
||||
return i.id
|
||||
}
|
||||
|
||||
func (i *image11) Dispose() {
|
||||
i.disposeBuffers()
|
||||
i.graphics.removeImage(i)
|
||||
}
|
||||
|
||||
func (i *image11) disposeBuffers() {
|
||||
if i.texture != nil {
|
||||
i.texture.Release()
|
||||
i.texture = nil
|
||||
}
|
||||
if i.stencil != nil {
|
||||
i.stencil.Release()
|
||||
i.stencil = nil
|
||||
}
|
||||
if i.renderTargetView != nil {
|
||||
i.renderTargetView.Release()
|
||||
i.renderTargetView = nil
|
||||
}
|
||||
if i.stencilView != nil {
|
||||
i.stencilView.Release()
|
||||
i.stencilView = nil
|
||||
}
|
||||
if i.shaderResourceView != nil {
|
||||
i.shaderResourceView.Release()
|
||||
i.shaderResourceView = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (i *image11) IsInvalidated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (i *image11) ReadPixels(buf []byte, x, y, width, height int) error {
|
||||
staging, err := i.graphics.device.CreateTexture2D(&_D3D11_TEXTURE2D_DESC{
|
||||
Width: uint32(width),
|
||||
Height: uint32(height),
|
||||
MipLevels: 0,
|
||||
ArraySize: 1,
|
||||
Format: _DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
SampleDesc: _DXGI_SAMPLE_DESC{
|
||||
Count: 1,
|
||||
Quality: 0,
|
||||
},
|
||||
Usage: _D3D11_USAGE_STAGING,
|
||||
BindFlags: 0,
|
||||
CPUAccessFlags: uint32(_D3D11_CPU_ACCESS_READ),
|
||||
MiscFlags: 0,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer staging.Release()
|
||||
|
||||
i.graphics.deviceContext.CopySubresourceRegion(unsafe.Pointer(staging), 0, 0, 0, 0, unsafe.Pointer(i.texture), 0, &_D3D11_BOX{
|
||||
left: uint32(x),
|
||||
top: uint32(y),
|
||||
front: 0,
|
||||
right: uint32(x + width),
|
||||
bottom: uint32(y + height),
|
||||
back: 1,
|
||||
})
|
||||
|
||||
var mapped _D3D11_MAPPED_SUBRESOURCE
|
||||
if err := i.graphics.deviceContext.Map(unsafe.Pointer(staging), 0, _D3D11_MAP_READ, 0, &mapped); err != nil {
|
||||
return err
|
||||
}
|
||||
copy(buf, unsafe.Slice((*byte)(mapped.pData), 4*width*height))
|
||||
i.graphics.deviceContext.Unmap(unsafe.Pointer(staging), 0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *image11) WritePixels(args []*graphicsdriver.WritePixelsArgs) error {
|
||||
for _, a := range args {
|
||||
i.graphics.deviceContext.UpdateSubresource(unsafe.Pointer(i.texture), 0, &_D3D11_BOX{
|
||||
left: uint32(a.X),
|
||||
top: uint32(a.Y),
|
||||
front: 0,
|
||||
right: uint32(a.X + a.Width),
|
||||
bottom: uint32(a.Y + a.Height),
|
||||
back: 1,
|
||||
}, unsafe.Pointer(&a.Pixels[0]), uint32(4*a.Width), 0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *image11) setAsRenderTarget(useStencil bool) error {
|
||||
if i.renderTargetView == nil {
|
||||
rtv, err := i.graphics.device.CreateRenderTargetView(unsafe.Pointer(i.texture), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.renderTargetView = rtv
|
||||
}
|
||||
|
||||
if !useStencil {
|
||||
i.graphics.deviceContext.OMSetRenderTargets([]*_ID3D11RenderTargetView{i.renderTargetView}, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
if i.screen {
|
||||
return fmt.Errorf("directx: a stencil buffer is not available for a screen image")
|
||||
}
|
||||
|
||||
if i.stencil == nil {
|
||||
w, h := i.internalSize()
|
||||
s, err := i.graphics.device.CreateTexture2D(&_D3D11_TEXTURE2D_DESC{
|
||||
Width: uint32(w),
|
||||
Height: uint32(h),
|
||||
MipLevels: 0,
|
||||
ArraySize: 1,
|
||||
Format: _DXGI_FORMAT_D24_UNORM_S8_UINT,
|
||||
SampleDesc: _DXGI_SAMPLE_DESC{
|
||||
Count: 1,
|
||||
Quality: 0,
|
||||
},
|
||||
Usage: _D3D11_USAGE_DEFAULT,
|
||||
BindFlags: uint32(_D3D11_BIND_DEPTH_STENCIL),
|
||||
CPUAccessFlags: 0,
|
||||
MiscFlags: 0,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.stencil = s
|
||||
}
|
||||
|
||||
if i.stencilView == nil {
|
||||
sv, err := i.graphics.device.CreateDepthStencilView(unsafe.Pointer(i.stencil), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.stencilView = sv
|
||||
}
|
||||
|
||||
i.graphics.deviceContext.OMSetRenderTargets([]*_ID3D11RenderTargetView{i.renderTargetView}, i.stencilView)
|
||||
i.graphics.deviceContext.ClearDepthStencilView(i.stencilView, uint8(_D3D11_CLEAR_STENCIL), 0, 0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *image11) getShaderResourceView() (*_ID3D11ShaderResourceView, error) {
|
||||
if i.shaderResourceView == nil {
|
||||
srv, err := i.graphics.device.CreateShaderResourceView(unsafe.Pointer(i.texture), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i.shaderResourceView = srv
|
||||
}
|
||||
return i.shaderResourceView, nil
|
||||
}
|
195
internal/graphicsdriver/directx/shader11_windows.go
Normal file
195
internal/graphicsdriver/directx/shader11_windows.go
Normal file
@ -0,0 +1,195 @@
|
||||
// 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 (
|
||||
"unsafe"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||
)
|
||||
|
||||
type shader11 struct {
|
||||
graphics *graphics11
|
||||
id graphicsdriver.ShaderID
|
||||
uniformTypes []shaderir.Type
|
||||
uniformOffsets []int
|
||||
vertexShaderBlob *_ID3DBlob
|
||||
pixelShaderBlob *_ID3DBlob
|
||||
|
||||
inputLayout *_ID3D11InputLayout
|
||||
vertexShader *_ID3D11VertexShader
|
||||
pixelShader *_ID3D11PixelShader
|
||||
constantBuffer *_ID3D11Buffer
|
||||
}
|
||||
|
||||
func (s *shader11) ID() graphicsdriver.ShaderID {
|
||||
return s.id
|
||||
}
|
||||
|
||||
func (s *shader11) Dispose() {
|
||||
s.graphics.removeShader(s)
|
||||
}
|
||||
|
||||
func (s *shader11) disposeImpl() {
|
||||
if s.pixelShaderBlob != nil {
|
||||
s.pixelShaderBlob.Release()
|
||||
s.pixelShaderBlob = nil
|
||||
}
|
||||
if s.vertexShaderBlob != nil {
|
||||
count := s.vertexShaderBlob.Release()
|
||||
if count == 0 {
|
||||
for k, v := range vertexShaderCache {
|
||||
if v == s.vertexShaderBlob {
|
||||
delete(vertexShaderCache, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
s.vertexShader = nil
|
||||
}
|
||||
if s.inputLayout != nil {
|
||||
s.inputLayout.Release()
|
||||
s.inputLayout = nil
|
||||
}
|
||||
if s.vertexShader != nil {
|
||||
s.vertexShader.Release()
|
||||
s.vertexShader = nil
|
||||
}
|
||||
if s.pixelShader != nil {
|
||||
s.pixelShader.Release()
|
||||
s.pixelShader = nil
|
||||
}
|
||||
if s.constantBuffer != nil {
|
||||
s.constantBuffer.Release()
|
||||
s.constantBuffer = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *shader11) use(uniforms []uint32, srcs [graphics.ShaderImageCount]*image11) error {
|
||||
vs, err := s.ensureVertexShader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.graphics.deviceContext.VSSetShader(vs, nil)
|
||||
|
||||
ps, err := s.ensurePixelShader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.graphics.deviceContext.PSSetShader(ps, nil)
|
||||
|
||||
il, err := s.ensureInputLayout()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.graphics.deviceContext.IASetInputLayout(il)
|
||||
|
||||
cb, err := s.ensureConstantBuffer()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.graphics.deviceContext.VSSetConstantBuffers(0, []*_ID3D11Buffer{cb})
|
||||
s.graphics.deviceContext.PSSetConstantBuffers(0, []*_ID3D11Buffer{cb})
|
||||
|
||||
// Send the constant buffer data.
|
||||
uniforms = adjustUniforms(s.uniformTypes, s.uniformOffsets, uniforms)
|
||||
var mapped _D3D11_MAPPED_SUBRESOURCE
|
||||
if err := s.graphics.deviceContext.Map(unsafe.Pointer(cb), 0, _D3D11_MAP_WRITE_DISCARD, 0, &mapped); err != nil {
|
||||
return err
|
||||
}
|
||||
copy(unsafe.Slice((*uint32)(mapped.pData), len(uniforms)), uniforms)
|
||||
s.graphics.deviceContext.Unmap(unsafe.Pointer(cb), 0)
|
||||
|
||||
// Set the render sources.
|
||||
var srvs [graphics.ShaderImageCount]*_ID3D11ShaderResourceView
|
||||
for i, src := range srcs {
|
||||
if src == nil {
|
||||
continue
|
||||
}
|
||||
srv, err := src.getShaderResourceView()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srvs[i] = srv
|
||||
}
|
||||
s.graphics.deviceContext.PSSetShaderResources(0, srvs[:])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *shader11) ensureInputLayout() (*_ID3D11InputLayout, error) {
|
||||
if s.inputLayout != nil {
|
||||
return s.inputLayout, nil
|
||||
}
|
||||
|
||||
i, err := s.graphics.device.CreateInputLayout(inputElementDescsForDX11, s.vertexShaderBlob.GetBufferPointer(), s.vertexShaderBlob.GetBufferSize())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.inputLayout = i
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (s *shader11) ensureVertexShader() (*_ID3D11VertexShader, error) {
|
||||
if s.vertexShader != nil {
|
||||
return s.vertexShader, nil
|
||||
}
|
||||
|
||||
vs, err := s.graphics.device.CreateVertexShader(s.vertexShaderBlob.GetBufferPointer(), s.vertexShaderBlob.GetBufferSize(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.vertexShader = vs
|
||||
return vs, nil
|
||||
}
|
||||
|
||||
func (s *shader11) ensurePixelShader() (*_ID3D11PixelShader, error) {
|
||||
if s.pixelShader != nil {
|
||||
return s.pixelShader, nil
|
||||
}
|
||||
|
||||
ps, err := s.graphics.device.CreatePixelShader(s.pixelShaderBlob.GetBufferPointer(), s.pixelShaderBlob.GetBufferSize(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.pixelShader = ps
|
||||
return ps, nil
|
||||
}
|
||||
|
||||
func alignUp16(x uint32) uint32 {
|
||||
if x%16 == 0 {
|
||||
return x
|
||||
}
|
||||
return x + 16 - (x % 16)
|
||||
}
|
||||
|
||||
func (s *shader11) ensureConstantBuffer() (*_ID3D11Buffer, error) {
|
||||
if s.constantBuffer != nil {
|
||||
return s.constantBuffer, nil
|
||||
}
|
||||
|
||||
cb, err := s.graphics.device.CreateBuffer(&_D3D11_BUFFER_DESC{
|
||||
ByteWidth: alignUp16(uint32(constantBufferSize(s.uniformTypes, s.uniformOffsets)) * 4),
|
||||
Usage: _D3D11_USAGE_DYNAMIC,
|
||||
BindFlags: uint32(_D3D11_BIND_CONSTANT_BUFFER),
|
||||
CPUAccessFlags: uint32(_D3D11_CPU_ACCESS_WRITE),
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.constantBuffer = cb
|
||||
return cb, nil
|
||||
}
|
@ -80,6 +80,59 @@ func compileShader(vs, ps string) (vsh, psh *_ID3DBlob, ferr error) {
|
||||
return
|
||||
}
|
||||
|
||||
func constantBufferSize(uniformTypes []shaderir.Type, uniformOffsets []int) int {
|
||||
var size int
|
||||
for i, typ := range uniformTypes {
|
||||
if size < uniformOffsets[i]/4 {
|
||||
size = uniformOffsets[i] / 4
|
||||
}
|
||||
|
||||
switch typ.Main {
|
||||
case shaderir.Float:
|
||||
size += 1
|
||||
case shaderir.Int:
|
||||
size += 1
|
||||
case shaderir.Vec2, shaderir.IVec2:
|
||||
size += 2
|
||||
case shaderir.Vec3, shaderir.IVec3:
|
||||
size += 3
|
||||
case shaderir.Vec4, shaderir.IVec4:
|
||||
size += 4
|
||||
case shaderir.Mat2:
|
||||
size += 6
|
||||
case shaderir.Mat3:
|
||||
size += 11
|
||||
case shaderir.Mat4:
|
||||
size += 16
|
||||
case shaderir.Array:
|
||||
// Each element is aligned to the boundary.
|
||||
switch typ.Sub[0].Main {
|
||||
case shaderir.Float:
|
||||
size += 4*(typ.Length-1) + 1
|
||||
case shaderir.Int:
|
||||
size += 4*(typ.Length-1) + 1
|
||||
case shaderir.Vec2, shaderir.IVec2:
|
||||
size += 4*(typ.Length-1) + 2
|
||||
case shaderir.Vec3, shaderir.IVec3:
|
||||
size += 4*(typ.Length-1) + 3
|
||||
case shaderir.Vec4, shaderir.IVec4:
|
||||
size += 4 * typ.Length
|
||||
case shaderir.Mat2:
|
||||
size += 8*(typ.Length-1) + 6
|
||||
case shaderir.Mat3:
|
||||
size += 12*(typ.Length-1) + 11
|
||||
case shaderir.Mat4:
|
||||
size += 16 * typ.Length
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: not implemented type for uniform variables: %s", typ.String()))
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("directx: not implemented type for uniform variables: %s", typ.String()))
|
||||
}
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
func adjustUniforms(uniformTypes []shaderir.Type, uniformOffsets []int, uniforms []uint32) []uint32 {
|
||||
var fs []uint32
|
||||
var idx int
|
||||
|
Loading…
Reference in New Issue
Block a user