Files
gio/gpu/internal/d3d11/d3d11_windows.go
T
Elias Naur 7d84e419c9 gpu,gpu/headless,app/internal/wm: add explicit RenderTarget API
Both the OpenGL and the Direct3D API are stateful and gpu.GPU renders to
the render target current when Frame is called.

Modern GPU API such as Metal don't have a concept of a current render
target, and the target even changes each frame.

Add RenderTarget and add an explicit target argument to GPU.Frame as
well as the underlying driver.Device.BeginFrame.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-08-08 13:45:23 +01:00

779 lines
21 KiB
Go

// SPDX-License-Identifier: Unlicense OR MIT
package d3d11
import (
"errors"
"fmt"
"image"
"math"
"reflect"
"unsafe"
"golang.org/x/sys/windows"
"gioui.org/gpu/internal/driver"
"gioui.org/internal/d3d11"
)
type Backend struct {
dev *d3d11.Device
ctx *d3d11.DeviceContext
// Temporary storage to avoid garbage.
clearColor [4]float32
viewport d3d11.VIEWPORT
depthState depthState
blendState blendState
// Current program.
prog *Program
caps driver.Caps
// fbo is the currently bound fbo.
fbo *Framebuffer
floatFormat uint32
// cached state objects.
depthStates map[depthState]*d3d11.DepthStencilState
blendStates map[blendState]*d3d11.BlendState
}
type blendState struct {
enable bool
sfactor driver.BlendFactor
dfactor driver.BlendFactor
}
type depthState struct {
enable bool
mask bool
fn driver.DepthFunc
}
type Texture struct {
backend *Backend
format uint32
bindings driver.BufferBinding
tex *d3d11.Texture2D
sampler *d3d11.SamplerState
resView *d3d11.ShaderResourceView
width int
height int
}
type Program struct {
backend *Backend
vert struct {
shader *d3d11.VertexShader
uniforms *Buffer
}
frag struct {
shader *d3d11.PixelShader
uniforms *Buffer
}
}
type Framebuffer struct {
dev *d3d11.Device
ctx *d3d11.DeviceContext
format uint32
resource *d3d11.Resource
renderTarget *d3d11.RenderTargetView
depthView *d3d11.DepthStencilView
foreign bool
}
type Buffer struct {
backend *Backend
bind uint32
buf *d3d11.Buffer
immutable bool
}
type InputLayout struct {
layout *d3d11.InputLayout
}
func init() {
driver.NewDirect3D11Device = newDirect3D11Device
}
func detectFloatFormat(dev *d3d11.Device) (uint32, bool) {
formats := []uint32{
d3d11.DXGI_FORMAT_R16_FLOAT,
d3d11.DXGI_FORMAT_R32_FLOAT,
d3d11.DXGI_FORMAT_R16G16_FLOAT,
d3d11.DXGI_FORMAT_R32G32_FLOAT,
// These last two are really wasteful, but c'est la vie.
d3d11.DXGI_FORMAT_R16G16B16A16_FLOAT,
d3d11.DXGI_FORMAT_R32G32B32A32_FLOAT,
}
for _, format := range formats {
need := uint32(d3d11.FORMAT_SUPPORT_TEXTURE2D | d3d11.FORMAT_SUPPORT_RENDER_TARGET)
if support, _ := dev.CheckFormatSupport(format); support&need == need {
return format, true
}
}
return 0, false
}
func newDirect3D11Device(api driver.Direct3D11) (driver.Device, error) {
dev := (*d3d11.Device)(api.Device)
b := &Backend{
dev: dev,
ctx: dev.GetImmediateContext(),
caps: driver.Caps{
MaxTextureSize: 2048, // 9.1 maximum
Features: driver.FeatureSRGB,
},
depthStates: make(map[depthState]*d3d11.DepthStencilState),
blendStates: make(map[blendState]*d3d11.BlendState),
}
featLvl := dev.GetFeatureLevel()
if featLvl < d3d11.FEATURE_LEVEL_9_1 {
d3d11.IUnknownRelease(unsafe.Pointer(dev), dev.Vtbl.Release)
d3d11.IUnknownRelease(unsafe.Pointer(b.ctx), b.ctx.Vtbl.Release)
return nil, fmt.Errorf("d3d11: feature level too low: %d", featLvl)
}
switch {
case featLvl >= d3d11.FEATURE_LEVEL_11_0:
b.caps.MaxTextureSize = 16384
case featLvl >= d3d11.FEATURE_LEVEL_9_3:
b.caps.MaxTextureSize = 4096
}
if fmt, ok := detectFloatFormat(dev); ok {
b.floatFormat = fmt
b.caps.Features |= driver.FeatureFloatRenderTargets
}
// Enable depth mask to match OpenGL.
b.depthState.mask = true
// Disable backface culling to match OpenGL.
state, err := dev.CreateRasterizerState(&d3d11.RASTERIZER_DESC{
CullMode: d3d11.CULL_NONE,
FillMode: d3d11.FILL_SOLID,
DepthClipEnable: 1,
})
if err != nil {
return nil, err
}
defer d3d11.IUnknownRelease(unsafe.Pointer(state), state.Vtbl.Release)
b.ctx.RSSetState(state)
return b, nil
}
func (b *Backend) BeginFrame(target driver.RenderTarget, clear bool, viewport image.Point) driver.Framebuffer {
var (
renderTarget *d3d11.RenderTargetView
depthView *d3d11.DepthStencilView
)
if target != nil {
switch t := target.(type) {
case driver.Direct3D11RenderTarget:
renderTarget = (*d3d11.RenderTargetView)(t.RenderTarget)
depthView = (*d3d11.DepthStencilView)(t.DepthStencilView)
case *Framebuffer:
renderTarget, depthView = t.renderTarget, t.depthView
default:
panic(fmt.Errorf("opengl: invalid render target type: %T", target))
}
}
b.ctx.OMSetRenderTargets(renderTarget, depthView)
return &Framebuffer{ctx: b.ctx, dev: b.dev, renderTarget: renderTarget, depthView: depthView, foreign: true}
}
func (b *Backend) BlitFramebuffer(dst, src driver.Framebuffer, srect, drect image.Rectangle) {
panic("not implemented")
}
func (b *Backend) EndFrame() {
}
func (b *Backend) Caps() driver.Caps {
return b.caps
}
func (b *Backend) NewTimer() driver.Timer {
panic("timers not supported")
}
func (b *Backend) IsTimeContinuous() bool {
panic("timers not supported")
}
func (b *Backend) Release() {
for _, state := range b.depthStates {
d3d11.IUnknownRelease(unsafe.Pointer(state), state.Vtbl.Release)
}
for _, state := range b.blendStates {
d3d11.IUnknownRelease(unsafe.Pointer(state), state.Vtbl.Release)
}
d3d11.IUnknownRelease(unsafe.Pointer(b.ctx), b.ctx.Vtbl.Release)
*b = Backend{}
}
func (b *Backend) NewTexture(format driver.TextureFormat, width, height int, minFilter, magFilter driver.TextureFilter, bindings driver.BufferBinding) (driver.Texture, error) {
var d3dfmt uint32
switch format {
case driver.TextureFormatFloat:
d3dfmt = b.floatFormat
case driver.TextureFormatSRGBA:
d3dfmt = d3d11.DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
default:
return nil, fmt.Errorf("unsupported texture format %d", format)
}
tex, err := b.dev.CreateTexture2D(&d3d11.TEXTURE2D_DESC{
Width: uint32(width),
Height: uint32(height),
MipLevels: 1,
ArraySize: 1,
Format: d3dfmt,
SampleDesc: d3d11.DXGI_SAMPLE_DESC{
Count: 1,
Quality: 0,
},
BindFlags: convBufferBinding(bindings),
})
if err != nil {
return nil, err
}
var (
sampler *d3d11.SamplerState
resView *d3d11.ShaderResourceView
)
if bindings&driver.BufferBindingTexture != 0 {
var filter uint32
switch {
case minFilter == driver.FilterNearest && magFilter == driver.FilterNearest:
filter = d3d11.FILTER_MIN_MAG_MIP_POINT
case minFilter == driver.FilterLinear && magFilter == driver.FilterLinear:
filter = d3d11.FILTER_MIN_MAG_LINEAR_MIP_POINT
default:
d3d11.IUnknownRelease(unsafe.Pointer(tex), tex.Vtbl.Release)
return nil, fmt.Errorf("unsupported texture filter combination %d, %d", minFilter, magFilter)
}
var err error
sampler, err = b.dev.CreateSamplerState(&d3d11.SAMPLER_DESC{
Filter: filter,
AddressU: d3d11.TEXTURE_ADDRESS_CLAMP,
AddressV: d3d11.TEXTURE_ADDRESS_CLAMP,
AddressW: d3d11.TEXTURE_ADDRESS_CLAMP,
MaxAnisotropy: 1,
MinLOD: -math.MaxFloat32,
MaxLOD: math.MaxFloat32,
})
if err != nil {
d3d11.IUnknownRelease(unsafe.Pointer(tex), tex.Vtbl.Release)
return nil, err
}
resView, err = b.dev.CreateShaderResourceViewTEX2D(
(*d3d11.Resource)(unsafe.Pointer(tex)),
&d3d11.SHADER_RESOURCE_VIEW_DESC_TEX2D{
SHADER_RESOURCE_VIEW_DESC: d3d11.SHADER_RESOURCE_VIEW_DESC{
Format: d3dfmt,
ViewDimension: d3d11.SRV_DIMENSION_TEXTURE2D,
},
Texture2D: d3d11.TEX2D_SRV{
MostDetailedMip: 0,
MipLevels: ^uint32(0),
},
},
)
if err != nil {
d3d11.IUnknownRelease(unsafe.Pointer(tex), tex.Vtbl.Release)
d3d11.IUnknownRelease(unsafe.Pointer(sampler), sampler.Vtbl.Release)
return nil, err
}
}
return &Texture{backend: b, format: d3dfmt, tex: tex, sampler: sampler, resView: resView, bindings: bindings, width: width, height: height}, nil
}
func (b *Backend) NewFramebuffer(tex driver.Texture, depthBits int) (driver.Framebuffer, error) {
d3dtex := tex.(*Texture)
if d3dtex.bindings&driver.BufferBindingFramebuffer == 0 {
return nil, errors.New("the texture was created without BufferBindingFramebuffer binding")
}
resource := (*d3d11.Resource)(unsafe.Pointer(d3dtex.tex))
renderTarget, err := b.dev.CreateRenderTargetView(resource)
if err != nil {
return nil, err
}
fbo := &Framebuffer{ctx: b.ctx, dev: b.dev, format: d3dtex.format, resource: resource, renderTarget: renderTarget}
if depthBits > 0 {
depthView, err := d3d11.CreateDepthView(b.dev, d3dtex.width, d3dtex.height, depthBits)
if err != nil {
d3d11.IUnknownRelease(unsafe.Pointer(renderTarget), renderTarget.Vtbl.Release)
return nil, err
}
fbo.depthView = depthView
}
return fbo, nil
}
func (b *Backend) NewInputLayout(vertexShader driver.ShaderSources, layout []driver.InputDesc) (driver.InputLayout, error) {
if len(vertexShader.Inputs) != len(layout) {
return nil, fmt.Errorf("NewInputLayout: got %d inputs, expected %d", len(layout), len(vertexShader.Inputs))
}
descs := make([]d3d11.INPUT_ELEMENT_DESC, len(layout))
for i, l := range layout {
inp := vertexShader.Inputs[i]
cname, err := windows.BytePtrFromString(inp.Semantic)
if err != nil {
return nil, err
}
var format uint32
switch l.Type {
case driver.DataTypeFloat:
switch l.Size {
case 1:
format = d3d11.DXGI_FORMAT_R32_FLOAT
case 2:
format = d3d11.DXGI_FORMAT_R32G32_FLOAT
case 3:
format = d3d11.DXGI_FORMAT_R32G32B32_FLOAT
case 4:
format = d3d11.DXGI_FORMAT_R32G32B32A32_FLOAT
default:
panic("unsupported data size")
}
case driver.DataTypeShort:
switch l.Size {
case 1:
format = d3d11.DXGI_FORMAT_R16_SINT
case 2:
format = d3d11.DXGI_FORMAT_R16G16_SINT
default:
panic("unsupported data size")
}
default:
panic("unsupported data type")
}
descs[i] = d3d11.INPUT_ELEMENT_DESC{
SemanticName: cname,
SemanticIndex: uint32(inp.SemanticIndex),
Format: format,
AlignedByteOffset: uint32(l.Offset),
}
}
l, err := b.dev.CreateInputLayout(descs, []byte(vertexShader.HLSL))
if err != nil {
return nil, err
}
return &InputLayout{layout: l}, nil
}
func (b *Backend) NewBuffer(typ driver.BufferBinding, size int) (driver.Buffer, error) {
if typ&driver.BufferBindingUniforms != 0 {
if typ != driver.BufferBindingUniforms {
return nil, errors.New("uniform buffers cannot have other bindings")
}
if size%16 != 0 {
return nil, fmt.Errorf("constant buffer size is %d, expected a multiple of 16", size)
}
}
bind := convBufferBinding(typ)
buf, err := b.dev.CreateBuffer(&d3d11.BUFFER_DESC{
ByteWidth: uint32(size),
BindFlags: bind,
}, nil)
if err != nil {
return nil, err
}
return &Buffer{backend: b, buf: buf, bind: bind}, nil
}
func (b *Backend) NewImmutableBuffer(typ driver.BufferBinding, data []byte) (driver.Buffer, error) {
if typ&driver.BufferBindingUniforms != 0 {
if typ != driver.BufferBindingUniforms {
return nil, errors.New("uniform buffers cannot have other bindings")
}
if len(data)%16 != 0 {
return nil, fmt.Errorf("constant buffer size is %d, expected a multiple of 16", len(data))
}
}
bind := convBufferBinding(typ)
buf, err := b.dev.CreateBuffer(&d3d11.BUFFER_DESC{
ByteWidth: uint32(len(data)),
Usage: d3d11.USAGE_IMMUTABLE,
BindFlags: bind,
}, data)
if err != nil {
return nil, err
}
return &Buffer{backend: b, buf: buf, bind: bind, immutable: true}, nil
}
func (b *Backend) NewComputeProgram(shader driver.ShaderSources) (driver.Program, error) {
panic("not implemented")
}
func (b *Backend) NewProgram(vertexShader, fragmentShader driver.ShaderSources) (driver.Program, error) {
vs, err := b.dev.CreateVertexShader([]byte(vertexShader.HLSL))
if err != nil {
return nil, err
}
ps, err := b.dev.CreatePixelShader([]byte(fragmentShader.HLSL))
if err != nil {
return nil, err
}
p := &Program{backend: b}
p.vert.shader = vs
p.frag.shader = ps
return p, nil
}
func (b *Backend) Clear(colr, colg, colb, cola float32) {
b.clearColor = [4]float32{colr, colg, colb, cola}
b.ctx.ClearRenderTargetView(b.fbo.renderTarget, &b.clearColor)
}
func (b *Backend) ClearDepth(depth float32) {
if b.fbo.depthView != nil {
b.ctx.ClearDepthStencilView(b.fbo.depthView, d3d11.CLEAR_DEPTH|d3d11.CLEAR_STENCIL, depth, 0)
}
}
func (b *Backend) Viewport(x, y, width, height int) {
b.viewport = d3d11.VIEWPORT{
TopLeftX: float32(x),
TopLeftY: float32(y),
Width: float32(width),
Height: float32(height),
MinDepth: 0.0,
MaxDepth: 1.0,
}
b.ctx.RSSetViewports(&b.viewport)
}
func (b *Backend) DrawArrays(mode driver.DrawMode, off, count int) {
b.prepareDraw(mode)
b.ctx.Draw(uint32(count), uint32(off))
}
func (b *Backend) DrawElements(mode driver.DrawMode, off, count int) {
b.prepareDraw(mode)
b.ctx.DrawIndexed(uint32(count), uint32(off), 0)
}
func (b *Backend) prepareDraw(mode driver.DrawMode) {
if p := b.prog; p != nil {
b.ctx.VSSetShader(p.vert.shader)
b.ctx.PSSetShader(p.frag.shader)
if buf := p.vert.uniforms; buf != nil {
b.ctx.VSSetConstantBuffers(buf.buf)
}
if buf := p.frag.uniforms; buf != nil {
b.ctx.PSSetConstantBuffers(buf.buf)
}
}
var topology uint32
switch mode {
case driver.DrawModeTriangles:
topology = d3d11.PRIMITIVE_TOPOLOGY_TRIANGLELIST
case driver.DrawModeTriangleStrip:
topology = d3d11.PRIMITIVE_TOPOLOGY_TRIANGLESTRIP
default:
panic("unsupported draw mode")
}
b.ctx.IASetPrimitiveTopology(topology)
depthState, ok := b.depthStates[b.depthState]
if !ok {
var desc d3d11.DEPTH_STENCIL_DESC
if b.depthState.enable {
desc.DepthEnable = 1
}
if b.depthState.mask {
desc.DepthWriteMask = d3d11.DEPTH_WRITE_MASK_ALL
}
switch b.depthState.fn {
case driver.DepthFuncGreater:
desc.DepthFunc = d3d11.COMPARISON_GREATER
case driver.DepthFuncGreaterEqual:
desc.DepthFunc = d3d11.COMPARISON_GREATER_EQUAL
default:
panic("unsupported depth func")
}
var err error
depthState, err = b.dev.CreateDepthStencilState(&desc)
if err != nil {
panic(err)
}
b.depthStates[b.depthState] = depthState
}
b.ctx.OMSetDepthStencilState(depthState, 0)
blendState, ok := b.blendStates[b.blendState]
if !ok {
var desc d3d11.BLEND_DESC
t0 := &desc.RenderTarget[0]
t0.RenderTargetWriteMask = d3d11.COLOR_WRITE_ENABLE_ALL
t0.BlendOp = d3d11.BLEND_OP_ADD
t0.BlendOpAlpha = d3d11.BLEND_OP_ADD
if b.blendState.enable {
t0.BlendEnable = 1
}
scol, salpha := toBlendFactor(b.blendState.sfactor)
dcol, dalpha := toBlendFactor(b.blendState.dfactor)
t0.SrcBlend = scol
t0.SrcBlendAlpha = salpha
t0.DestBlend = dcol
t0.DestBlendAlpha = dalpha
var err error
blendState, err = b.dev.CreateBlendState(&desc)
if err != nil {
panic(err)
}
b.blendStates[b.blendState] = blendState
}
b.ctx.OMSetBlendState(blendState, nil, 0xffffffff)
}
func (b *Backend) DepthFunc(f driver.DepthFunc) {
b.depthState.fn = f
}
func (b *Backend) SetBlend(enable bool) {
b.blendState.enable = enable
}
func (b *Backend) SetDepthTest(enable bool) {
b.depthState.enable = enable
}
func (b *Backend) DepthMask(mask bool) {
b.depthState.mask = mask
}
func (b *Backend) BlendFunc(sfactor, dfactor driver.BlendFactor) {
b.blendState.sfactor = sfactor
b.blendState.dfactor = dfactor
}
func (b *Backend) BindImageTexture(unit int, tex driver.Texture, access driver.AccessBits, f driver.TextureFormat) {
panic("not implemented")
}
func (b *Backend) MemoryBarrier() {
panic("not implemented")
}
func (b *Backend) DispatchCompute(x, y, z int) {
panic("not implemented")
}
func (t *Texture) Upload(offset, size image.Point, pixels []byte, stride int) {
if stride == 0 {
stride = size.X * 4
}
dst := &d3d11.BOX{
Left: uint32(offset.X),
Top: uint32(offset.Y),
Right: uint32(offset.X + size.X),
Bottom: uint32(offset.Y + size.Y),
Front: 0,
Back: 1,
}
res := (*d3d11.Resource)(unsafe.Pointer(t.tex))
t.backend.ctx.UpdateSubresource(res, dst, uint32(stride), uint32(len(pixels)), pixels)
}
func (t *Texture) Release() {
d3d11.IUnknownRelease(unsafe.Pointer(t.tex), t.tex.Vtbl.Release)
t.tex = nil
if t.sampler != nil {
d3d11.IUnknownRelease(unsafe.Pointer(t.sampler), t.sampler.Vtbl.Release)
t.sampler = nil
}
if t.resView != nil {
d3d11.IUnknownRelease(unsafe.Pointer(t.resView), t.resView.Vtbl.Release)
t.resView = nil
}
}
func (b *Backend) BindTexture(unit int, tex driver.Texture) {
t := tex.(*Texture)
b.ctx.PSSetSamplers(uint32(unit), t.sampler)
b.ctx.PSSetShaderResources(uint32(unit), t.resView)
}
func (b *Backend) BindProgram(prog driver.Program) {
b.prog = prog.(*Program)
}
func (p *Program) Release() {
d3d11.IUnknownRelease(unsafe.Pointer(p.vert.shader), p.vert.shader.Vtbl.Release)
d3d11.IUnknownRelease(unsafe.Pointer(p.frag.shader), p.frag.shader.Vtbl.Release)
p.vert.shader = nil
p.frag.shader = nil
}
func (p *Program) SetStorageBuffer(binding int, buffer driver.Buffer) {
panic("not implemented")
}
func (p *Program) SetVertexUniforms(buf driver.Buffer) {
p.vert.uniforms = buf.(*Buffer)
}
func (p *Program) SetFragmentUniforms(buf driver.Buffer) {
p.frag.uniforms = buf.(*Buffer)
}
func (b *Backend) BindVertexBuffer(buf driver.Buffer, stride, offset int) {
b.ctx.IASetVertexBuffers(buf.(*Buffer).buf, uint32(stride), uint32(offset))
}
func (b *Backend) BindIndexBuffer(buf driver.Buffer) {
b.ctx.IASetIndexBuffer(buf.(*Buffer).buf, d3d11.DXGI_FORMAT_R16_UINT, 0)
}
func (b *Buffer) Download(data []byte) error {
panic("not implemented")
}
func (b *Buffer) Upload(data []byte) {
b.backend.ctx.UpdateSubresource((*d3d11.Resource)(unsafe.Pointer(b.buf)), nil, 0, 0, data)
}
func (b *Buffer) Release() {
d3d11.IUnknownRelease(unsafe.Pointer(b.buf), b.buf.Vtbl.Release)
b.buf = nil
}
func (f *Framebuffer) ReadPixels(src image.Rectangle, pixels []byte) error {
if f.resource == nil {
return errors.New("framebuffer does not support ReadPixels")
}
w, h := src.Dx(), src.Dy()
tex, err := f.dev.CreateTexture2D(&d3d11.TEXTURE2D_DESC{
Width: uint32(w),
Height: uint32(h),
MipLevels: 1,
ArraySize: 1,
Format: f.format,
SampleDesc: d3d11.DXGI_SAMPLE_DESC{
Count: 1,
Quality: 0,
},
Usage: d3d11.USAGE_STAGING,
CPUAccessFlags: d3d11.CPU_ACCESS_READ,
})
if err != nil {
return fmt.Errorf("ReadPixels: %v", err)
}
defer d3d11.IUnknownRelease(unsafe.Pointer(tex), tex.Vtbl.Release)
res := (*d3d11.Resource)(unsafe.Pointer(tex))
f.ctx.CopySubresourceRegion(
res,
0, // Destination subresource.
0, 0, 0, // Destination coordinates (x, y, z).
f.resource,
0, // Source subresource.
&d3d11.BOX{
Left: uint32(src.Min.X),
Top: uint32(src.Min.Y),
Right: uint32(src.Max.X),
Bottom: uint32(src.Max.Y),
Front: 0,
Back: 1,
},
)
resMap, err := f.ctx.Map(res, 0, d3d11.MAP_READ, 0)
if err != nil {
return fmt.Errorf("ReadPixels: %v", err)
}
defer f.ctx.Unmap(res, 0)
srcPitch := w * 4
dstPitch := int(resMap.RowPitch)
mapSize := dstPitch * h
data := sliceOf(resMap.PData, mapSize)
width := w * 4
for r := 0; r < h; r++ {
pixels := pixels[r*srcPitch:]
copy(pixels[:width], data[r*dstPitch:])
}
return nil
}
func (b *Backend) BindFramebuffer(fbo driver.Framebuffer) {
b.fbo = fbo.(*Framebuffer)
b.ctx.OMSetRenderTargets(b.fbo.renderTarget, b.fbo.depthView)
}
func (f *Framebuffer) Invalidate() {
}
func (f *Framebuffer) Release() {
if f.foreign {
panic("framebuffer not created by NewFramebuffer")
}
if f.renderTarget != nil {
d3d11.IUnknownRelease(unsafe.Pointer(f.renderTarget), f.renderTarget.Vtbl.Release)
f.renderTarget = nil
}
if f.depthView != nil {
d3d11.IUnknownRelease(unsafe.Pointer(f.depthView), f.depthView.Vtbl.Release)
f.depthView = nil
}
}
func (f *Framebuffer) ImplementsRenderTarget() {}
func (b *Backend) BindInputLayout(layout driver.InputLayout) {
b.ctx.IASetInputLayout(layout.(*InputLayout).layout)
}
func (l *InputLayout) Release() {
d3d11.IUnknownRelease(unsafe.Pointer(l.layout), l.layout.Vtbl.Release)
l.layout = nil
}
func convBufferBinding(typ driver.BufferBinding) uint32 {
var bindings uint32
if typ&driver.BufferBindingVertices != 0 {
bindings |= d3d11.BIND_VERTEX_BUFFER
}
if typ&driver.BufferBindingIndices != 0 {
bindings |= d3d11.BIND_INDEX_BUFFER
}
if typ&driver.BufferBindingUniforms != 0 {
bindings |= d3d11.BIND_CONSTANT_BUFFER
}
if typ&driver.BufferBindingTexture != 0 {
bindings |= d3d11.BIND_SHADER_RESOURCE
}
if typ&driver.BufferBindingFramebuffer != 0 {
bindings |= d3d11.BIND_RENDER_TARGET
}
return bindings
}
func toBlendFactor(f driver.BlendFactor) (uint32, uint32) {
switch f {
case driver.BlendFactorOne:
return d3d11.BLEND_ONE, d3d11.BLEND_ONE
case driver.BlendFactorOneMinusSrcAlpha:
return d3d11.BLEND_INV_SRC_ALPHA, d3d11.BLEND_INV_SRC_ALPHA
case driver.BlendFactorZero:
return d3d11.BLEND_ZERO, d3d11.BLEND_ZERO
case driver.BlendFactorDstColor:
return d3d11.BLEND_DEST_COLOR, d3d11.BLEND_DEST_ALPHA
default:
panic("unsupported blend source factor")
}
}
// sliceOf returns a slice from a (native) pointer.
func sliceOf(ptr uintptr, cap int) []byte {
var data []byte
h := (*reflect.SliceHeader)(unsafe.Pointer(&data))
h.Data = ptr
h.Cap = cap
h.Len = cap
return data
}