123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876 |
- // SPDX-License-Identifier: Unlicense OR MIT
- package d3d11
- import (
- "errors"
- "fmt"
- "image"
- "math"
- "math/bits"
- "unsafe"
- "golang.org/x/sys/windows"
- "gioui.org/gpu/internal/driver"
- "gioui.org/internal/d3d11"
- "gioui.org/shader"
- )
- type Backend struct {
- dev *d3d11.Device
- ctx *d3d11.DeviceContext
- // Temporary storage to avoid garbage.
- clearColor [4]float32
- viewport d3d11.VIEWPORT
- pipeline *Pipeline
- vert struct {
- buffer *Buffer
- offset int
- }
- program *Program
- caps driver.Caps
- floatFormat uint32
- }
- type Pipeline struct {
- vert *d3d11.VertexShader
- frag *d3d11.PixelShader
- layout *d3d11.InputLayout
- blend *d3d11.BlendState
- stride int
- topology driver.Topology
- }
- type Texture struct {
- backend *Backend
- format uint32
- bindings driver.BufferBinding
- tex *d3d11.Texture2D
- sampler *d3d11.SamplerState
- resView *d3d11.ShaderResourceView
- uaView *d3d11.UnorderedAccessView
- renderTarget *d3d11.RenderTargetView
- width int
- height int
- mipmap bool
- foreign bool
- }
- type VertexShader struct {
- backend *Backend
- shader *d3d11.VertexShader
- src shader.Sources
- }
- type FragmentShader struct {
- backend *Backend
- shader *d3d11.PixelShader
- }
- type Program struct {
- backend *Backend
- shader *d3d11.ComputeShader
- }
- type Buffer struct {
- backend *Backend
- bind uint32
- buf *d3d11.Buffer
- resView *d3d11.ShaderResourceView
- uaView *d3d11.UnorderedAccessView
- size int
- immutable bool
- }
- 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,
- },
- }
- featLvl := dev.GetFeatureLevel()
- switch {
- case 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)
- case featLvl >= d3d11.FEATURE_LEVEL_11_0:
- b.caps.MaxTextureSize = 16384
- b.caps.Features |= driver.FeatureCompute
- 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
- }
- // Disable backface culling to match OpenGL.
- state, err := dev.CreateRasterizerState(&d3d11.RASTERIZER_DESC{
- CullMode: d3d11.CULL_NONE,
- FillMode: d3d11.FILL_SOLID,
- })
- 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.Texture {
- var (
- renderTarget *d3d11.RenderTargetView
- )
- if target != nil {
- switch t := target.(type) {
- case driver.Direct3D11RenderTarget:
- renderTarget = (*d3d11.RenderTargetView)(t.RenderTarget)
- case *Texture:
- renderTarget = t.renderTarget
- default:
- panic(fmt.Errorf("d3d11: invalid render target type: %T", target))
- }
- }
- b.ctx.OMSetRenderTargets(renderTarget, nil)
- return &Texture{backend: b, renderTarget: renderTarget, foreign: true}
- }
- func (b *Backend) CopyTexture(dstTex driver.Texture, dstOrigin image.Point, srcTex driver.Texture, srcRect image.Rectangle) {
- dst := (*d3d11.Resource)(unsafe.Pointer(dstTex.(*Texture).tex))
- src := (*d3d11.Resource)(srcTex.(*Texture).tex)
- b.ctx.CopySubresourceRegion(
- dst,
- 0, // Destination subresource.
- uint32(dstOrigin.X), uint32(dstOrigin.Y), 0, // Destination coordinates (x, y, z).
- src,
- 0, // Source subresource.
- &d3d11.BOX{
- Left: uint32(srcRect.Min.X),
- Top: uint32(srcRect.Min.Y),
- Right: uint32(srcRect.Max.X),
- Bottom: uint32(srcRect.Max.Y),
- Front: 0,
- Back: 1,
- },
- )
- }
- 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() {
- 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
- case driver.TextureFormatRGBA8:
- d3dfmt = d3d11.DXGI_FORMAT_R8G8B8A8_UNORM
- default:
- return nil, fmt.Errorf("unsupported texture format %d", format)
- }
- bindFlags := convBufferBinding(bindings)
- miscFlags := uint32(0)
- mipmap := minFilter == driver.FilterLinearMipmapLinear
- nmipmaps := 1
- if mipmap {
- // Flags required by ID3D11DeviceContext::GenerateMips.
- bindFlags |= d3d11.BIND_SHADER_RESOURCE | d3d11.BIND_RENDER_TARGET
- miscFlags |= d3d11.RESOURCE_MISC_GENERATE_MIPS
- dim := width
- if height > dim {
- dim = height
- }
- log2 := 32 - bits.LeadingZeros32(uint32(dim)) - 1
- nmipmaps = log2 + 1
- }
- tex, err := b.dev.CreateTexture2D(&d3d11.TEXTURE2D_DESC{
- Width: uint32(width),
- Height: uint32(height),
- MipLevels: uint32(nmipmaps),
- ArraySize: 1,
- Format: d3dfmt,
- SampleDesc: d3d11.DXGI_SAMPLE_DESC{
- Count: 1,
- Quality: 0,
- },
- BindFlags: bindFlags,
- MiscFlags: miscFlags,
- })
- if err != nil {
- return nil, err
- }
- var (
- sampler *d3d11.SamplerState
- resView *d3d11.ShaderResourceView
- uaView *d3d11.UnorderedAccessView
- fbo *d3d11.RenderTargetView
- )
- 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
- case minFilter == driver.FilterLinearMipmapLinear && magFilter == driver.FilterLinear:
- filter = d3d11.FILTER_MIN_MAG_MIP_LINEAR
- 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.CreateShaderResourceView(
- (*d3d11.Resource)(unsafe.Pointer(tex)),
- unsafe.Pointer(&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
- }
- }
- if bindings&driver.BufferBindingShaderStorageWrite != 0 {
- uaView, err = b.dev.CreateUnorderedAccessView(
- (*d3d11.Resource)(unsafe.Pointer(tex)),
- unsafe.Pointer(&d3d11.UNORDERED_ACCESS_VIEW_DESC_TEX2D{
- UNORDERED_ACCESS_VIEW_DESC: d3d11.UNORDERED_ACCESS_VIEW_DESC{
- Format: d3dfmt,
- ViewDimension: d3d11.UAV_DIMENSION_TEXTURE2D,
- },
- Texture2D: d3d11.TEX2D_UAV{
- MipSlice: 0,
- },
- }),
- )
- if err != nil {
- if sampler != nil {
- d3d11.IUnknownRelease(unsafe.Pointer(sampler), sampler.Vtbl.Release)
- }
- if resView != nil {
- d3d11.IUnknownRelease(unsafe.Pointer(resView), resView.Vtbl.Release)
- }
- d3d11.IUnknownRelease(unsafe.Pointer(tex), tex.Vtbl.Release)
- return nil, err
- }
- }
- if bindings&driver.BufferBindingFramebuffer != 0 {
- resource := (*d3d11.Resource)(unsafe.Pointer(tex))
- fbo, err = b.dev.CreateRenderTargetView(resource)
- if err != nil {
- if uaView != nil {
- d3d11.IUnknownRelease(unsafe.Pointer(uaView), uaView.Vtbl.Release)
- }
- if sampler != nil {
- d3d11.IUnknownRelease(unsafe.Pointer(sampler), sampler.Vtbl.Release)
- }
- if resView != nil {
- d3d11.IUnknownRelease(unsafe.Pointer(resView), resView.Vtbl.Release)
- }
- d3d11.IUnknownRelease(unsafe.Pointer(tex), tex.Vtbl.Release)
- return nil, err
- }
- }
- return &Texture{backend: b, format: d3dfmt, tex: tex, sampler: sampler, resView: resView, uaView: uaView, renderTarget: fbo, bindings: bindings, width: width, height: height, mipmap: mipmap}, nil
- }
- func (b *Backend) newInputLayout(vertexShader shader.Sources, layout []driver.InputDesc) (*d3d11.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 shader.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 shader.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),
- }
- }
- return b.dev.CreateInputLayout(descs, []byte(vertexShader.DXBC))
- }
- func (b *Backend) NewBuffer(typ driver.BufferBinding, size int) (driver.Buffer, error) {
- return b.newBuffer(typ, size, nil, false)
- }
- func (b *Backend) NewImmutableBuffer(typ driver.BufferBinding, data []byte) (driver.Buffer, error) {
- return b.newBuffer(typ, len(data), data, true)
- }
- func (b *Backend) newBuffer(typ driver.BufferBinding, size int, data []byte, immutable bool) (*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)
- var usage, miscFlags, cpuFlags uint32
- if immutable {
- usage = d3d11.USAGE_IMMUTABLE
- }
- if typ&driver.BufferBindingShaderStorageWrite != 0 {
- cpuFlags = d3d11.CPU_ACCESS_READ
- }
- if typ&(driver.BufferBindingShaderStorageRead|driver.BufferBindingShaderStorageWrite) != 0 {
- miscFlags |= d3d11.RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS
- }
- buf, err := b.dev.CreateBuffer(&d3d11.BUFFER_DESC{
- ByteWidth: uint32(size),
- Usage: usage,
- BindFlags: bind,
- CPUAccessFlags: cpuFlags,
- MiscFlags: miscFlags,
- }, data)
- if err != nil {
- return nil, err
- }
- var (
- resView *d3d11.ShaderResourceView
- uaView *d3d11.UnorderedAccessView
- )
- if typ&driver.BufferBindingShaderStorageWrite != 0 {
- uaView, err = b.dev.CreateUnorderedAccessView(
- (*d3d11.Resource)(unsafe.Pointer(buf)),
- unsafe.Pointer(&d3d11.UNORDERED_ACCESS_VIEW_DESC_BUFFER{
- UNORDERED_ACCESS_VIEW_DESC: d3d11.UNORDERED_ACCESS_VIEW_DESC{
- Format: d3d11.DXGI_FORMAT_R32_TYPELESS,
- ViewDimension: d3d11.UAV_DIMENSION_BUFFER,
- },
- Buffer: d3d11.BUFFER_UAV{
- FirstElement: 0,
- NumElements: uint32(size / 4),
- Flags: d3d11.BUFFER_UAV_FLAG_RAW,
- },
- }),
- )
- if err != nil {
- d3d11.IUnknownRelease(unsafe.Pointer(buf), buf.Vtbl.Release)
- return nil, err
- }
- } else if typ&driver.BufferBindingShaderStorageRead != 0 {
- resView, err = b.dev.CreateShaderResourceView(
- (*d3d11.Resource)(unsafe.Pointer(buf)),
- unsafe.Pointer(&d3d11.SHADER_RESOURCE_VIEW_DESC_BUFFEREX{
- SHADER_RESOURCE_VIEW_DESC: d3d11.SHADER_RESOURCE_VIEW_DESC{
- Format: d3d11.DXGI_FORMAT_R32_TYPELESS,
- ViewDimension: d3d11.SRV_DIMENSION_BUFFEREX,
- },
- Buffer: d3d11.BUFFEREX_SRV{
- FirstElement: 0,
- NumElements: uint32(size / 4),
- Flags: d3d11.BUFFEREX_SRV_FLAG_RAW,
- },
- }),
- )
- if err != nil {
- d3d11.IUnknownRelease(unsafe.Pointer(buf), buf.Vtbl.Release)
- return nil, err
- }
- }
- return &Buffer{backend: b, buf: buf, bind: bind, size: size, resView: resView, uaView: uaView, immutable: immutable}, nil
- }
- func (b *Backend) NewComputeProgram(shader shader.Sources) (driver.Program, error) {
- cs, err := b.dev.CreateComputeShader([]byte(shader.DXBC))
- if err != nil {
- return nil, err
- }
- return &Program{backend: b, shader: cs}, nil
- }
- func (b *Backend) NewPipeline(desc driver.PipelineDesc) (driver.Pipeline, error) {
- vsh := desc.VertexShader.(*VertexShader)
- fsh := desc.FragmentShader.(*FragmentShader)
- blend, err := b.newBlendState(desc.BlendDesc)
- if err != nil {
- return nil, err
- }
- var layout *d3d11.InputLayout
- if l := desc.VertexLayout; l.Stride > 0 {
- var err error
- layout, err = b.newInputLayout(vsh.src, l.Inputs)
- if err != nil {
- d3d11.IUnknownRelease(unsafe.Pointer(blend), blend.Vtbl.AddRef)
- return nil, err
- }
- }
- // Retain shaders.
- vshRef := vsh.shader
- fshRef := fsh.shader
- d3d11.IUnknownAddRef(unsafe.Pointer(vshRef), vshRef.Vtbl.AddRef)
- d3d11.IUnknownAddRef(unsafe.Pointer(fshRef), fshRef.Vtbl.AddRef)
- return &Pipeline{
- vert: vshRef,
- frag: fshRef,
- layout: layout,
- stride: desc.VertexLayout.Stride,
- blend: blend,
- topology: desc.Topology,
- }, nil
- }
- func (b *Backend) newBlendState(desc driver.BlendDesc) (*d3d11.BlendState, error) {
- var d3ddesc d3d11.BLEND_DESC
- t0 := &d3ddesc.RenderTarget[0]
- t0.RenderTargetWriteMask = d3d11.COLOR_WRITE_ENABLE_ALL
- t0.BlendOp = d3d11.BLEND_OP_ADD
- t0.BlendOpAlpha = d3d11.BLEND_OP_ADD
- if desc.Enable {
- t0.BlendEnable = 1
- }
- scol, salpha := toBlendFactor(desc.SrcFactor)
- dcol, dalpha := toBlendFactor(desc.DstFactor)
- t0.SrcBlend = scol
- t0.SrcBlendAlpha = salpha
- t0.DestBlend = dcol
- t0.DestBlendAlpha = dalpha
- return b.dev.CreateBlendState(&d3ddesc)
- }
- func (b *Backend) NewVertexShader(src shader.Sources) (driver.VertexShader, error) {
- vs, err := b.dev.CreateVertexShader([]byte(src.DXBC))
- if err != nil {
- return nil, err
- }
- return &VertexShader{b, vs, src}, nil
- }
- func (b *Backend) NewFragmentShader(src shader.Sources) (driver.FragmentShader, error) {
- fs, err := b.dev.CreatePixelShader([]byte(src.DXBC))
- if err != nil {
- return nil, err
- }
- return &FragmentShader{b, fs}, nil
- }
- 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(off, count int) {
- b.prepareDraw()
- b.ctx.Draw(uint32(count), uint32(off))
- }
- func (b *Backend) DrawElements(off, count int) {
- b.prepareDraw()
- b.ctx.DrawIndexed(uint32(count), uint32(off), 0)
- }
- func (b *Backend) prepareDraw() {
- p := b.pipeline
- if p == nil {
- return
- }
- b.ctx.VSSetShader(p.vert)
- b.ctx.PSSetShader(p.frag)
- b.ctx.IASetInputLayout(p.layout)
- b.ctx.OMSetBlendState(p.blend, nil, 0xffffffff)
- if b.vert.buffer != nil {
- b.ctx.IASetVertexBuffers(b.vert.buffer.buf, uint32(p.stride), uint32(b.vert.offset))
- }
- var topology uint32
- switch p.topology {
- case driver.TopologyTriangles:
- topology = d3d11.PRIMITIVE_TOPOLOGY_TRIANGLELIST
- case driver.TopologyTriangleStrip:
- topology = d3d11.PRIMITIVE_TOPOLOGY_TRIANGLESTRIP
- default:
- panic("unsupported draw mode")
- }
- b.ctx.IASetPrimitiveTopology(topology)
- }
- func (b *Backend) BindImageTexture(unit int, tex driver.Texture) {
- t := tex.(*Texture)
- if t.uaView != nil {
- b.ctx.CSSetUnorderedAccessViews(uint32(unit), t.uaView)
- } else {
- b.ctx.CSSetShaderResources(uint32(unit), t.resView)
- }
- }
- func (b *Backend) DispatchCompute(x, y, z int) {
- b.ctx.CSSetShader(b.program.shader)
- b.ctx.Dispatch(uint32(x), uint32(y), uint32(z))
- }
- 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)
- if t.mipmap {
- t.backend.ctx.GenerateMips(t.resView)
- }
- }
- func (t *Texture) Release() {
- if t.foreign {
- panic("texture not created by NewTexture")
- }
- if t.renderTarget != nil {
- d3d11.IUnknownRelease(unsafe.Pointer(t.renderTarget), t.renderTarget.Vtbl.Release)
- }
- if t.sampler != nil {
- d3d11.IUnknownRelease(unsafe.Pointer(t.sampler), t.sampler.Vtbl.Release)
- }
- if t.resView != nil {
- d3d11.IUnknownRelease(unsafe.Pointer(t.resView), t.resView.Vtbl.Release)
- }
- if t.uaView != nil {
- d3d11.IUnknownRelease(unsafe.Pointer(t.uaView), t.uaView.Vtbl.Release)
- }
- d3d11.IUnknownRelease(unsafe.Pointer(t.tex), t.tex.Vtbl.Release)
- *t = Texture{}
- }
- func (b *Backend) PrepareTexture(tex driver.Texture) {}
- 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) BindPipeline(pipe driver.Pipeline) {
- b.pipeline = pipe.(*Pipeline)
- }
- func (b *Backend) BindProgram(prog driver.Program) {
- b.program = prog.(*Program)
- }
- func (s *VertexShader) Release() {
- d3d11.IUnknownRelease(unsafe.Pointer(s.shader), s.shader.Vtbl.Release)
- *s = VertexShader{}
- }
- func (s *FragmentShader) Release() {
- d3d11.IUnknownRelease(unsafe.Pointer(s.shader), s.shader.Vtbl.Release)
- *s = FragmentShader{}
- }
- func (s *Program) Release() {
- d3d11.IUnknownRelease(unsafe.Pointer(s.shader), s.shader.Vtbl.Release)
- *s = Program{}
- }
- func (p *Pipeline) Release() {
- d3d11.IUnknownRelease(unsafe.Pointer(p.vert), p.vert.Vtbl.Release)
- d3d11.IUnknownRelease(unsafe.Pointer(p.frag), p.frag.Vtbl.Release)
- d3d11.IUnknownRelease(unsafe.Pointer(p.blend), p.blend.Vtbl.Release)
- if l := p.layout; l != nil {
- d3d11.IUnknownRelease(unsafe.Pointer(l), l.Vtbl.Release)
- }
- *p = Pipeline{}
- }
- func (b *Backend) BindStorageBuffer(binding int, buffer driver.Buffer) {
- buf := buffer.(*Buffer)
- if buf.resView != nil {
- b.ctx.CSSetShaderResources(uint32(binding), buf.resView)
- } else {
- b.ctx.CSSetUnorderedAccessViews(uint32(binding), buf.uaView)
- }
- }
- func (b *Backend) BindUniforms(buffer driver.Buffer) {
- buf := buffer.(*Buffer)
- b.ctx.VSSetConstantBuffers(buf.buf)
- b.ctx.PSSetConstantBuffers(buf.buf)
- }
- func (b *Backend) BindVertexBuffer(buf driver.Buffer, offset int) {
- b.vert.buffer = buf.(*Buffer)
- b.vert.offset = offset
- }
- func (b *Backend) BindIndexBuffer(buf driver.Buffer) {
- b.ctx.IASetIndexBuffer(buf.(*Buffer).buf, d3d11.DXGI_FORMAT_R16_UINT, 0)
- }
- func (b *Buffer) Download(dst []byte) error {
- res := (*d3d11.Resource)(unsafe.Pointer(b.buf))
- resMap, err := b.backend.ctx.Map(res, 0, d3d11.MAP_READ, 0)
- if err != nil {
- return fmt.Errorf("d3d11: %v", err)
- }
- defer b.backend.ctx.Unmap(res, 0)
- data := sliceOf(resMap.PData, len(dst))
- copy(dst, data)
- return nil
- }
- func (b *Buffer) Upload(data []byte) {
- var dst *d3d11.BOX
- if len(data) < b.size {
- dst = &d3d11.BOX{
- Left: 0,
- Right: uint32(len(data)),
- Top: 0,
- Bottom: 1,
- Front: 0,
- Back: 1,
- }
- }
- b.backend.ctx.UpdateSubresource((*d3d11.Resource)(unsafe.Pointer(b.buf)), dst, 0, 0, data)
- }
- func (b *Buffer) Release() {
- if b.resView != nil {
- d3d11.IUnknownRelease(unsafe.Pointer(b.resView), b.resView.Vtbl.Release)
- }
- if b.uaView != nil {
- d3d11.IUnknownRelease(unsafe.Pointer(b.uaView), b.uaView.Vtbl.Release)
- }
- d3d11.IUnknownRelease(unsafe.Pointer(b.buf), b.buf.Vtbl.Release)
- *b = Buffer{}
- }
- func (t *Texture) ReadPixels(src image.Rectangle, pixels []byte, stride int) error {
- w, h := src.Dx(), src.Dy()
- tex, err := t.backend.dev.CreateTexture2D(&d3d11.TEXTURE2D_DESC{
- Width: uint32(w),
- Height: uint32(h),
- MipLevels: 1,
- ArraySize: 1,
- Format: t.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))
- t.backend.ctx.CopySubresourceRegion(
- res,
- 0, // Destination subresource.
- 0, 0, 0, // Destination coordinates (x, y, z).
- (*d3d11.Resource)(t.tex),
- 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 := t.backend.ctx.Map(res, 0, d3d11.MAP_READ, 0)
- if err != nil {
- return fmt.Errorf("ReadPixels: %v", err)
- }
- defer t.backend.ctx.Unmap(res, 0)
- srcPitch := stride
- 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) BeginCompute() {
- }
- func (b *Backend) EndCompute() {
- }
- func (b *Backend) BeginRenderPass(tex driver.Texture, d driver.LoadDesc) {
- t := tex.(*Texture)
- b.ctx.OMSetRenderTargets(t.renderTarget, nil)
- if d.Action == driver.LoadActionClear {
- c := d.ClearColor
- b.clearColor = [4]float32{c.R, c.G, c.B, c.A}
- b.ctx.ClearRenderTargetView(t.renderTarget, &b.clearColor)
- }
- }
- func (b *Backend) EndRenderPass() {
- }
- func (f *Texture) ImplementsRenderTarget() {}
- 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
- }
- if typ&driver.BufferBindingShaderStorageWrite != 0 {
- bindings |= d3d11.BIND_UNORDERED_ACCESS
- } else if typ&driver.BufferBindingShaderStorageRead != 0 {
- bindings |= d3d11.BIND_SHADER_RESOURCE
- }
- 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 {
- return unsafe.Slice((*byte)(unsafe.Pointer(ptr)), cap)
- }
|