d3d11_windows.go raw

   1  // SPDX-License-Identifier: Unlicense OR MIT
   2  
   3  package d3d11
   4  
   5  import (
   6  	"errors"
   7  	"fmt"
   8  	"image"
   9  	"math"
  10  	"reflect"
  11  	"unsafe"
  12  
  13  	"golang.org/x/sys/windows"
  14  
  15  	"github.com/p9c/p9/pkg/gel/gio/gpu/internal/driver"
  16  	"github.com/p9c/p9/pkg/gel/gio/internal/d3d11"
  17  )
  18  
  19  type Backend struct {
  20  	dev *d3d11.Device
  21  	ctx *d3d11.DeviceContext
  22  
  23  	// Temporary storage to avoid garbage.
  24  	clearColor [4]float32
  25  	viewport   d3d11.VIEWPORT
  26  	depthState depthState
  27  	blendState blendState
  28  
  29  	// Current program.
  30  	prog *Program
  31  
  32  	caps driver.Caps
  33  
  34  	// fbo is the currently bound fbo.
  35  	fbo *Framebuffer
  36  
  37  	floatFormat uint32
  38  
  39  	// cached state objects.
  40  	depthStates map[depthState]*d3d11.DepthStencilState
  41  	blendStates map[blendState]*d3d11.BlendState
  42  }
  43  
  44  type blendState struct {
  45  	enable  bool
  46  	sfactor driver.BlendFactor
  47  	dfactor driver.BlendFactor
  48  }
  49  
  50  type depthState struct {
  51  	enable bool
  52  	mask   bool
  53  	fn     driver.DepthFunc
  54  }
  55  
  56  type Texture struct {
  57  	backend  *Backend
  58  	format   uint32
  59  	bindings driver.BufferBinding
  60  	tex      *d3d11.Texture2D
  61  	sampler  *d3d11.SamplerState
  62  	resView  *d3d11.ShaderResourceView
  63  	width    int
  64  	height   int
  65  }
  66  
  67  type Program struct {
  68  	backend *Backend
  69  
  70  	vert struct {
  71  		shader   *d3d11.VertexShader
  72  		uniforms *Buffer
  73  	}
  74  	frag struct {
  75  		shader   *d3d11.PixelShader
  76  		uniforms *Buffer
  77  	}
  78  }
  79  
  80  type Framebuffer struct {
  81  	dev          *d3d11.Device
  82  	ctx          *d3d11.DeviceContext
  83  	format       uint32
  84  	resource     *d3d11.Resource
  85  	renderTarget *d3d11.RenderTargetView
  86  	depthView    *d3d11.DepthStencilView
  87  	foreign      bool
  88  }
  89  
  90  type Buffer struct {
  91  	backend   *Backend
  92  	bind      uint32
  93  	buf       *d3d11.Buffer
  94  	immutable bool
  95  }
  96  
  97  type InputLayout struct {
  98  	layout *d3d11.InputLayout
  99  }
 100  
 101  func init() {
 102  	driver.NewDirect3D11Device = newDirect3D11Device
 103  }
 104  
 105  func detectFloatFormat(dev *d3d11.Device) (uint32, bool) {
 106  	formats := []uint32{
 107  		d3d11.DXGI_FORMAT_R16_FLOAT,
 108  		d3d11.DXGI_FORMAT_R32_FLOAT,
 109  		d3d11.DXGI_FORMAT_R16G16_FLOAT,
 110  		d3d11.DXGI_FORMAT_R32G32_FLOAT,
 111  		// These last two are really wasteful, but c'est la vie.
 112  		d3d11.DXGI_FORMAT_R16G16B16A16_FLOAT,
 113  		d3d11.DXGI_FORMAT_R32G32B32A32_FLOAT,
 114  	}
 115  	for _, format := range formats {
 116  		need := uint32(d3d11.FORMAT_SUPPORT_TEXTURE2D | d3d11.FORMAT_SUPPORT_RENDER_TARGET)
 117  		if support, _ := dev.CheckFormatSupport(format); support&need == need {
 118  			return format, true
 119  		}
 120  	}
 121  	return 0, false
 122  }
 123  
 124  func newDirect3D11Device(api driver.Direct3D11) (driver.Device, error) {
 125  	dev := (*d3d11.Device)(api.Device)
 126  	b := &Backend{
 127  		dev: dev,
 128  		ctx: dev.GetImmediateContext(),
 129  		caps: driver.Caps{
 130  			MaxTextureSize: 2048, // 9.1 maximum
 131  		},
 132  		depthStates: make(map[depthState]*d3d11.DepthStencilState),
 133  		blendStates: make(map[blendState]*d3d11.BlendState),
 134  	}
 135  	featLvl := dev.GetFeatureLevel()
 136  	if featLvl < d3d11.FEATURE_LEVEL_9_1 {
 137  		d3d11.IUnknownRelease(unsafe.Pointer(dev), dev.Vtbl.Release)
 138  		d3d11.IUnknownRelease(unsafe.Pointer(b.ctx), b.ctx.Vtbl.Release)
 139  		return nil, fmt.Errorf("d3d11: feature level too low: %d", featLvl)
 140  	}
 141  	switch {
 142  	case featLvl >= d3d11.FEATURE_LEVEL_11_0:
 143  		b.caps.MaxTextureSize = 16384
 144  	case featLvl >= d3d11.FEATURE_LEVEL_9_3:
 145  		b.caps.MaxTextureSize = 4096
 146  	}
 147  	if fmt, ok := detectFloatFormat(dev); ok {
 148  		b.floatFormat = fmt
 149  		b.caps.Features |= driver.FeatureFloatRenderTargets
 150  	}
 151  	// Enable depth mask to match OpenGL.
 152  	b.depthState.mask = true
 153  	// Disable backface culling to match OpenGL.
 154  	state, err := dev.CreateRasterizerState(&d3d11.RASTERIZER_DESC{
 155  		CullMode:        d3d11.CULL_NONE,
 156  		FillMode:        d3d11.FILL_SOLID,
 157  		DepthClipEnable: 1,
 158  	})
 159  	if err != nil {
 160  		return nil, err
 161  	}
 162  	defer d3d11.IUnknownRelease(unsafe.Pointer(state), state.Vtbl.Release)
 163  	b.ctx.RSSetState(state)
 164  	return b, nil
 165  }
 166  
 167  func (b *Backend) BeginFrame() driver.Framebuffer {
 168  	renderTarget, depthView := b.ctx.OMGetRenderTargets()
 169  	// Assume someone else is holding on to the render targets.
 170  	if renderTarget != nil {
 171  		d3d11.IUnknownRelease(unsafe.Pointer(renderTarget), renderTarget.Vtbl.Release)
 172  	}
 173  	if depthView != nil {
 174  		d3d11.IUnknownRelease(unsafe.Pointer(depthView), depthView.Vtbl.Release)
 175  	}
 176  	return &Framebuffer{ctx: b.ctx, dev: b.dev, renderTarget: renderTarget, depthView: depthView, foreign: true}
 177  }
 178  
 179  func (b *Backend) EndFrame() {
 180  }
 181  
 182  func (b *Backend) Caps() driver.Caps {
 183  	return b.caps
 184  }
 185  
 186  func (b *Backend) NewTimer() driver.Timer {
 187  	panic("timers not supported")
 188  }
 189  
 190  func (b *Backend) IsTimeContinuous() bool {
 191  	panic("timers not supported")
 192  }
 193  
 194  func (b *Backend) Release() {
 195  	for _, state := range b.depthStates {
 196  		d3d11.IUnknownRelease(unsafe.Pointer(state), state.Vtbl.Release)
 197  	}
 198  	for _, state := range b.blendStates {
 199  		d3d11.IUnknownRelease(unsafe.Pointer(state), state.Vtbl.Release)
 200  	}
 201  	d3d11.IUnknownRelease(unsafe.Pointer(b.ctx), b.ctx.Vtbl.Release)
 202  	*b = Backend{}
 203  }
 204  
 205  func (b *Backend) NewTexture(format driver.TextureFormat, width, height int, minFilter, magFilter driver.TextureFilter, bindings driver.BufferBinding) (driver.Texture, error) {
 206  	var d3dfmt uint32
 207  	switch format {
 208  	case driver.TextureFormatFloat:
 209  		d3dfmt = b.floatFormat
 210  	case driver.TextureFormatSRGB:
 211  		d3dfmt = d3d11.DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
 212  	default:
 213  		return nil, fmt.Errorf("unsupported texture format %d", format)
 214  	}
 215  	tex, err := b.dev.CreateTexture2D(&d3d11.TEXTURE2D_DESC{
 216  		Width:     uint32(width),
 217  		Height:    uint32(height),
 218  		MipLevels: 1,
 219  		ArraySize: 1,
 220  		Format:    d3dfmt,
 221  		SampleDesc: d3d11.DXGI_SAMPLE_DESC{
 222  			Count:   1,
 223  			Quality: 0,
 224  		},
 225  		BindFlags: convBufferBinding(bindings),
 226  	})
 227  	if err != nil {
 228  		return nil, err
 229  	}
 230  	var (
 231  		sampler *d3d11.SamplerState
 232  		resView *d3d11.ShaderResourceView
 233  	)
 234  	if bindings&driver.BufferBindingTexture != 0 {
 235  		var filter uint32
 236  		switch {
 237  		case minFilter == driver.FilterNearest && magFilter == driver.FilterNearest:
 238  			filter = d3d11.FILTER_MIN_MAG_MIP_POINT
 239  		case minFilter == driver.FilterLinear && magFilter == driver.FilterLinear:
 240  			filter = d3d11.FILTER_MIN_MAG_LINEAR_MIP_POINT
 241  		default:
 242  			d3d11.IUnknownRelease(unsafe.Pointer(tex), tex.Vtbl.Release)
 243  			return nil, fmt.Errorf("unsupported texture filter combination %d, %d", minFilter, magFilter)
 244  		}
 245  		var err error
 246  		sampler, err = b.dev.CreateSamplerState(&d3d11.SAMPLER_DESC{
 247  			Filter:        filter,
 248  			AddressU:      d3d11.TEXTURE_ADDRESS_CLAMP,
 249  			AddressV:      d3d11.TEXTURE_ADDRESS_CLAMP,
 250  			AddressW:      d3d11.TEXTURE_ADDRESS_CLAMP,
 251  			MaxAnisotropy: 1,
 252  			MinLOD:        -math.MaxFloat32,
 253  			MaxLOD:        math.MaxFloat32,
 254  		})
 255  		if err != nil {
 256  			d3d11.IUnknownRelease(unsafe.Pointer(tex), tex.Vtbl.Release)
 257  			return nil, err
 258  		}
 259  		resView, err = b.dev.CreateShaderResourceViewTEX2D(
 260  			(*d3d11.Resource)(unsafe.Pointer(tex)),
 261  			&d3d11.SHADER_RESOURCE_VIEW_DESC_TEX2D{
 262  				SHADER_RESOURCE_VIEW_DESC: d3d11.SHADER_RESOURCE_VIEW_DESC{
 263  					Format:        d3dfmt,
 264  					ViewDimension: d3d11.SRV_DIMENSION_TEXTURE2D,
 265  				},
 266  				Texture2D: d3d11.TEX2D_SRV{
 267  					MostDetailedMip: 0,
 268  					MipLevels:       ^uint32(0),
 269  				},
 270  			},
 271  		)
 272  		if err != nil {
 273  			d3d11.IUnknownRelease(unsafe.Pointer(tex), tex.Vtbl.Release)
 274  			d3d11.IUnknownRelease(unsafe.Pointer(sampler), sampler.Vtbl.Release)
 275  			return nil, err
 276  		}
 277  	}
 278  	return &Texture{backend: b, format: d3dfmt, tex: tex, sampler: sampler, resView: resView, bindings: bindings, width: width, height: height}, nil
 279  }
 280  
 281  func (b *Backend) NewFramebuffer(tex driver.Texture, depthBits int) (driver.Framebuffer, error) {
 282  	d3dtex := tex.(*Texture)
 283  	if d3dtex.bindings&driver.BufferBindingFramebuffer == 0 {
 284  		return nil, errors.New("the texture was created without BufferBindingFramebuffer binding")
 285  	}
 286  	resource := (*d3d11.Resource)(unsafe.Pointer(d3dtex.tex))
 287  	renderTarget, err := b.dev.CreateRenderTargetView(resource)
 288  	if err != nil {
 289  		return nil, err
 290  	}
 291  	fbo := &Framebuffer{ctx: b.ctx, dev: b.dev, format: d3dtex.format, resource: resource, renderTarget: renderTarget}
 292  	if depthBits > 0 {
 293  		depthView, err := d3d11.CreateDepthView(b.dev, d3dtex.width, d3dtex.height, depthBits)
 294  		if err != nil {
 295  			d3d11.IUnknownRelease(unsafe.Pointer(renderTarget), renderTarget.Vtbl.Release)
 296  			return nil, err
 297  		}
 298  		fbo.depthView = depthView
 299  	}
 300  	return fbo, nil
 301  }
 302  
 303  func (b *Backend) NewInputLayout(vertexShader driver.ShaderSources, layout []driver.InputDesc) (driver.InputLayout, error) {
 304  	if len(vertexShader.Inputs) != len(layout) {
 305  		return nil, fmt.Errorf("NewInputLayout: got %d inputs, expected %d", len(layout), len(vertexShader.Inputs))
 306  	}
 307  	descs := make([]d3d11.INPUT_ELEMENT_DESC, len(layout))
 308  	for i, l := range layout {
 309  		inp := vertexShader.Inputs[i]
 310  		cname, err := windows.BytePtrFromString(inp.Semantic)
 311  		if err != nil {
 312  			return nil, err
 313  		}
 314  		var format uint32
 315  		switch l.Type {
 316  		case driver.DataTypeFloat:
 317  			switch l.Size {
 318  			case 1:
 319  				format = d3d11.DXGI_FORMAT_R32_FLOAT
 320  			case 2:
 321  				format = d3d11.DXGI_FORMAT_R32G32_FLOAT
 322  			case 3:
 323  				format = d3d11.DXGI_FORMAT_R32G32B32_FLOAT
 324  			case 4:
 325  				format = d3d11.DXGI_FORMAT_R32G32B32A32_FLOAT
 326  			default:
 327  				panic("unsupported data size")
 328  			}
 329  		case driver.DataTypeShort:
 330  			switch l.Size {
 331  			case 1:
 332  				format = d3d11.DXGI_FORMAT_R16_SINT
 333  			case 2:
 334  				format = d3d11.DXGI_FORMAT_R16G16_SINT
 335  			default:
 336  				panic("unsupported data size")
 337  			}
 338  		default:
 339  			panic("unsupported data type")
 340  		}
 341  		descs[i] = d3d11.INPUT_ELEMENT_DESC{
 342  			SemanticName:      cname,
 343  			SemanticIndex:     uint32(inp.SemanticIndex),
 344  			Format:            format,
 345  			AlignedByteOffset: uint32(l.Offset),
 346  		}
 347  	}
 348  	l, err := b.dev.CreateInputLayout(descs, []byte(vertexShader.HLSL))
 349  	if err != nil {
 350  		return nil, err
 351  	}
 352  	return &InputLayout{layout: l}, nil
 353  }
 354  
 355  func (b *Backend) NewBuffer(typ driver.BufferBinding, size int) (driver.Buffer, error) {
 356  	if typ&driver.BufferBindingUniforms != 0 {
 357  		if typ != driver.BufferBindingUniforms {
 358  			return nil, errors.New("uniform buffers cannot have other bindings")
 359  		}
 360  		if size%16 != 0 {
 361  			return nil, fmt.Errorf("constant buffer size is %d, expected a multiple of 16", size)
 362  		}
 363  	}
 364  	bind := convBufferBinding(typ)
 365  	buf, err := b.dev.CreateBuffer(&d3d11.BUFFER_DESC{
 366  		ByteWidth: uint32(size),
 367  		BindFlags: bind,
 368  	}, nil)
 369  	if err != nil {
 370  		return nil, err
 371  	}
 372  	return &Buffer{backend: b, buf: buf, bind: bind}, nil
 373  }
 374  
 375  func (b *Backend) NewImmutableBuffer(typ driver.BufferBinding, data []byte) (driver.Buffer, error) {
 376  	if typ&driver.BufferBindingUniforms != 0 {
 377  		if typ != driver.BufferBindingUniforms {
 378  			return nil, errors.New("uniform buffers cannot have other bindings")
 379  		}
 380  		if len(data)%16 != 0 {
 381  			return nil, fmt.Errorf("constant buffer size is %d, expected a multiple of 16", len(data))
 382  		}
 383  	}
 384  	bind := convBufferBinding(typ)
 385  	buf, err := b.dev.CreateBuffer(&d3d11.BUFFER_DESC{
 386  		ByteWidth: uint32(len(data)),
 387  		Usage:     d3d11.USAGE_IMMUTABLE,
 388  		BindFlags: bind,
 389  	}, data)
 390  	if err != nil {
 391  		return nil, err
 392  	}
 393  	return &Buffer{backend: b, buf: buf, bind: bind, immutable: true}, nil
 394  }
 395  
 396  func (b *Backend) NewComputeProgram(shader driver.ShaderSources) (driver.Program, error) {
 397  	panic("not implemented")
 398  }
 399  
 400  func (b *Backend) NewProgram(vertexShader, fragmentShader driver.ShaderSources) (driver.Program, error) {
 401  	vs, err := b.dev.CreateVertexShader([]byte(vertexShader.HLSL))
 402  	if err != nil {
 403  		return nil, err
 404  	}
 405  	ps, err := b.dev.CreatePixelShader([]byte(fragmentShader.HLSL))
 406  	if err != nil {
 407  		return nil, err
 408  	}
 409  	p := &Program{backend: b}
 410  	p.vert.shader = vs
 411  	p.frag.shader = ps
 412  	return p, nil
 413  }
 414  
 415  func (b *Backend) Clear(colr, colg, colb, cola float32) {
 416  	b.clearColor = [4]float32{colr, colg, colb, cola}
 417  	b.ctx.ClearRenderTargetView(b.fbo.renderTarget, &b.clearColor)
 418  }
 419  
 420  func (b *Backend) ClearDepth(depth float32) {
 421  	if b.fbo.depthView != nil {
 422  		b.ctx.ClearDepthStencilView(b.fbo.depthView, d3d11.CLEAR_DEPTH|d3d11.CLEAR_STENCIL, depth, 0)
 423  	}
 424  }
 425  
 426  func (b *Backend) Viewport(x, y, width, height int) {
 427  	b.viewport = d3d11.VIEWPORT{
 428  		TopLeftX: float32(x),
 429  		TopLeftY: float32(y),
 430  		Width:    float32(width),
 431  		Height:   float32(height),
 432  		MinDepth: 0.0,
 433  		MaxDepth: 1.0,
 434  	}
 435  	b.ctx.RSSetViewports(&b.viewport)
 436  }
 437  
 438  func (b *Backend) DrawArrays(mode driver.DrawMode, off, count int) {
 439  	b.prepareDraw(mode)
 440  	b.ctx.Draw(uint32(count), uint32(off))
 441  }
 442  
 443  func (b *Backend) DrawElements(mode driver.DrawMode, off, count int) {
 444  	b.prepareDraw(mode)
 445  	b.ctx.DrawIndexed(uint32(count), uint32(off), 0)
 446  }
 447  
 448  func (b *Backend) prepareDraw(mode driver.DrawMode) {
 449  	if p := b.prog; p != nil {
 450  		b.ctx.VSSetShader(p.vert.shader)
 451  		b.ctx.PSSetShader(p.frag.shader)
 452  		if buf := p.vert.uniforms; buf != nil {
 453  			b.ctx.VSSetConstantBuffers(buf.buf)
 454  		}
 455  		if buf := p.frag.uniforms; buf != nil {
 456  			b.ctx.PSSetConstantBuffers(buf.buf)
 457  		}
 458  	}
 459  	var topology uint32
 460  	switch mode {
 461  	case driver.DrawModeTriangles:
 462  		topology = d3d11.PRIMITIVE_TOPOLOGY_TRIANGLELIST
 463  	case driver.DrawModeTriangleStrip:
 464  		topology = d3d11.PRIMITIVE_TOPOLOGY_TRIANGLESTRIP
 465  	default:
 466  		panic("unsupported draw mode")
 467  	}
 468  	b.ctx.IASetPrimitiveTopology(topology)
 469  
 470  	depthState, ok := b.depthStates[b.depthState]
 471  	if !ok {
 472  		var desc d3d11.DEPTH_STENCIL_DESC
 473  		if b.depthState.enable {
 474  			desc.DepthEnable = 1
 475  		}
 476  		if b.depthState.mask {
 477  			desc.DepthWriteMask = d3d11.DEPTH_WRITE_MASK_ALL
 478  		}
 479  		switch b.depthState.fn {
 480  		case driver.DepthFuncGreater:
 481  			desc.DepthFunc = d3d11.COMPARISON_GREATER
 482  		case driver.DepthFuncGreaterEqual:
 483  			desc.DepthFunc = d3d11.COMPARISON_GREATER_EQUAL
 484  		default:
 485  			panic("unsupported depth func")
 486  		}
 487  		var err error
 488  		depthState, err = b.dev.CreateDepthStencilState(&desc)
 489  		if err != nil {
 490  			panic(err)
 491  		}
 492  		b.depthStates[b.depthState] = depthState
 493  	}
 494  	b.ctx.OMSetDepthStencilState(depthState, 0)
 495  
 496  	blendState, ok := b.blendStates[b.blendState]
 497  	if !ok {
 498  		var desc d3d11.BLEND_DESC
 499  		t0 := &desc.RenderTarget[0]
 500  		t0.RenderTargetWriteMask = d3d11.COLOR_WRITE_ENABLE_ALL
 501  		t0.BlendOp = d3d11.BLEND_OP_ADD
 502  		t0.BlendOpAlpha = d3d11.BLEND_OP_ADD
 503  		if b.blendState.enable {
 504  			t0.BlendEnable = 1
 505  		}
 506  		scol, salpha := toBlendFactor(b.blendState.sfactor)
 507  		dcol, dalpha := toBlendFactor(b.blendState.dfactor)
 508  		t0.SrcBlend = scol
 509  		t0.SrcBlendAlpha = salpha
 510  		t0.DestBlend = dcol
 511  		t0.DestBlendAlpha = dalpha
 512  		var err error
 513  		blendState, err = b.dev.CreateBlendState(&desc)
 514  		if err != nil {
 515  			panic(err)
 516  		}
 517  		b.blendStates[b.blendState] = blendState
 518  	}
 519  	b.ctx.OMSetBlendState(blendState, nil, 0xffffffff)
 520  }
 521  
 522  func (b *Backend) DepthFunc(f driver.DepthFunc) {
 523  	b.depthState.fn = f
 524  }
 525  
 526  func (b *Backend) SetBlend(enable bool) {
 527  	b.blendState.enable = enable
 528  }
 529  
 530  func (b *Backend) SetDepthTest(enable bool) {
 531  	b.depthState.enable = enable
 532  }
 533  
 534  func (b *Backend) DepthMask(mask bool) {
 535  	b.depthState.mask = mask
 536  }
 537  
 538  func (b *Backend) BlendFunc(sfactor, dfactor driver.BlendFactor) {
 539  	b.blendState.sfactor = sfactor
 540  	b.blendState.dfactor = dfactor
 541  }
 542  
 543  func (b *Backend) BindImageTexture(unit int, tex driver.Texture, access driver.AccessBits, f driver.TextureFormat) {
 544  	panic("not implemented")
 545  }
 546  
 547  func (b *Backend) MemoryBarrier() {
 548  	panic("not implemented")
 549  }
 550  
 551  func (b *Backend) DispatchCompute(x, y, z int) {
 552  	panic("not implemented")
 553  }
 554  
 555  func (t *Texture) Upload(offset, size image.Point, pixels []byte) {
 556  	stride := size.X * 4
 557  	dst := &d3d11.BOX{
 558  		Left:   uint32(offset.X),
 559  		Top:    uint32(offset.Y),
 560  		Right:  uint32(offset.X + size.X),
 561  		Bottom: uint32(offset.Y + size.Y),
 562  		Front:  0,
 563  		Back:   1,
 564  	}
 565  	res := (*d3d11.Resource)(unsafe.Pointer(t.tex))
 566  	t.backend.ctx.UpdateSubresource(res, dst, uint32(stride), uint32(len(pixels)), pixels)
 567  }
 568  
 569  func (t *Texture) Release() {
 570  	d3d11.IUnknownRelease(unsafe.Pointer(t.tex), t.tex.Vtbl.Release)
 571  	t.tex = nil
 572  	if t.sampler != nil {
 573  		d3d11.IUnknownRelease(unsafe.Pointer(t.sampler), t.sampler.Vtbl.Release)
 574  		t.sampler = nil
 575  	}
 576  	if t.resView != nil {
 577  		d3d11.IUnknownRelease(unsafe.Pointer(t.resView), t.resView.Vtbl.Release)
 578  		t.resView = nil
 579  	}
 580  }
 581  
 582  func (b *Backend) BindTexture(unit int, tex driver.Texture) {
 583  	t := tex.(*Texture)
 584  	b.ctx.PSSetSamplers(uint32(unit), t.sampler)
 585  	b.ctx.PSSetShaderResources(uint32(unit), t.resView)
 586  }
 587  
 588  func (b *Backend) BindProgram(prog driver.Program) {
 589  	b.prog = prog.(*Program)
 590  }
 591  
 592  func (p *Program) Release() {
 593  	d3d11.IUnknownRelease(unsafe.Pointer(p.vert.shader), p.vert.shader.Vtbl.Release)
 594  	d3d11.IUnknownRelease(unsafe.Pointer(p.frag.shader), p.frag.shader.Vtbl.Release)
 595  	p.vert.shader = nil
 596  	p.frag.shader = nil
 597  }
 598  
 599  func (p *Program) SetStorageBuffer(binding int, buffer driver.Buffer) {
 600  	panic("not implemented")
 601  }
 602  
 603  func (p *Program) SetVertexUniforms(buf driver.Buffer) {
 604  	p.vert.uniforms = buf.(*Buffer)
 605  }
 606  
 607  func (p *Program) SetFragmentUniforms(buf driver.Buffer) {
 608  	p.frag.uniforms = buf.(*Buffer)
 609  }
 610  
 611  func (b *Backend) BindVertexBuffer(buf driver.Buffer, stride, offset int) {
 612  	b.ctx.IASetVertexBuffers(buf.(*Buffer).buf, uint32(stride), uint32(offset))
 613  }
 614  
 615  func (b *Backend) BindIndexBuffer(buf driver.Buffer) {
 616  	b.ctx.IASetIndexBuffer(buf.(*Buffer).buf, d3d11.DXGI_FORMAT_R16_UINT, 0)
 617  }
 618  
 619  func (b *Buffer) Download(data []byte) error {
 620  	panic("not implemented")
 621  }
 622  
 623  func (b *Buffer) Upload(data []byte) {
 624  	b.backend.ctx.UpdateSubresource((*d3d11.Resource)(unsafe.Pointer(b.buf)), nil, 0, 0, data)
 625  }
 626  
 627  func (b *Buffer) Release() {
 628  	d3d11.IUnknownRelease(unsafe.Pointer(b.buf), b.buf.Vtbl.Release)
 629  	b.buf = nil
 630  }
 631  
 632  func (f *Framebuffer) ReadPixels(src image.Rectangle, pixels []byte) error {
 633  	if f.resource == nil {
 634  		return errors.New("framebuffer does not support ReadPixels")
 635  	}
 636  	w, h := src.Dx(), src.Dy()
 637  	tex, err := f.dev.CreateTexture2D(&d3d11.TEXTURE2D_DESC{
 638  		Width:     uint32(w),
 639  		Height:    uint32(h),
 640  		MipLevels: 1,
 641  		ArraySize: 1,
 642  		Format:    f.format,
 643  		SampleDesc: d3d11.DXGI_SAMPLE_DESC{
 644  			Count:   1,
 645  			Quality: 0,
 646  		},
 647  		Usage:          d3d11.USAGE_STAGING,
 648  		CPUAccessFlags: d3d11.CPU_ACCESS_READ,
 649  	})
 650  	if err != nil {
 651  		return fmt.Errorf("ReadPixels: %v", err)
 652  	}
 653  	defer d3d11.IUnknownRelease(unsafe.Pointer(tex), tex.Vtbl.Release)
 654  	res := (*d3d11.Resource)(unsafe.Pointer(tex))
 655  	f.ctx.CopySubresourceRegion(
 656  		res,
 657  		0,       // Destination subresource.
 658  		0, 0, 0, // Destination coordinates (x, y, z).
 659  		f.resource,
 660  		0, // Source subresource.
 661  		&d3d11.BOX{
 662  			Left:   uint32(src.Min.X),
 663  			Top:    uint32(src.Min.Y),
 664  			Right:  uint32(src.Max.X),
 665  			Bottom: uint32(src.Max.Y),
 666  			Front:  0,
 667  			Back:   1,
 668  		},
 669  	)
 670  	resMap, err := f.ctx.Map(res, 0, d3d11.MAP_READ, 0)
 671  	if err != nil {
 672  		return fmt.Errorf("ReadPixels: %v", err)
 673  	}
 674  	defer f.ctx.Unmap(res, 0)
 675  	srcPitch := w * 4
 676  	dstPitch := int(resMap.RowPitch)
 677  	mapSize := dstPitch * h
 678  	data := sliceOf(resMap.PData, mapSize)
 679  	width := w * 4
 680  	for r := 0; r < h; r++ {
 681  		pixels := pixels[r*srcPitch:]
 682  		copy(pixels[:width], data[r*dstPitch:])
 683  	}
 684  	return nil
 685  }
 686  
 687  func (b *Backend) BindFramebuffer(fbo driver.Framebuffer) {
 688  	b.fbo = fbo.(*Framebuffer)
 689  	b.ctx.OMSetRenderTargets(b.fbo.renderTarget, b.fbo.depthView)
 690  }
 691  
 692  func (f *Framebuffer) Invalidate() {
 693  }
 694  
 695  func (f *Framebuffer) Release() {
 696  	if f.foreign {
 697  		panic("framebuffer not created by NewFramebuffer")
 698  	}
 699  	if f.renderTarget != nil {
 700  		d3d11.IUnknownRelease(unsafe.Pointer(f.renderTarget), f.renderTarget.Vtbl.Release)
 701  		f.renderTarget = nil
 702  	}
 703  	if f.depthView != nil {
 704  		d3d11.IUnknownRelease(unsafe.Pointer(f.depthView), f.depthView.Vtbl.Release)
 705  		f.depthView = nil
 706  	}
 707  }
 708  
 709  func (b *Backend) BindInputLayout(layout driver.InputLayout) {
 710  	b.ctx.IASetInputLayout(layout.(*InputLayout).layout)
 711  }
 712  
 713  func (l *InputLayout) Release() {
 714  	d3d11.IUnknownRelease(unsafe.Pointer(l.layout), l.layout.Vtbl.Release)
 715  	l.layout = nil
 716  }
 717  
 718  func convBufferBinding(typ driver.BufferBinding) uint32 {
 719  	var bindings uint32
 720  	if typ&driver.BufferBindingVertices != 0 {
 721  		bindings |= d3d11.BIND_VERTEX_BUFFER
 722  	}
 723  	if typ&driver.BufferBindingIndices != 0 {
 724  		bindings |= d3d11.BIND_INDEX_BUFFER
 725  	}
 726  	if typ&driver.BufferBindingUniforms != 0 {
 727  		bindings |= d3d11.BIND_CONSTANT_BUFFER
 728  	}
 729  	if typ&driver.BufferBindingTexture != 0 {
 730  		bindings |= d3d11.BIND_SHADER_RESOURCE
 731  	}
 732  	if typ&driver.BufferBindingFramebuffer != 0 {
 733  		bindings |= d3d11.BIND_RENDER_TARGET
 734  	}
 735  	return bindings
 736  }
 737  
 738  func toBlendFactor(f driver.BlendFactor) (uint32, uint32) {
 739  	switch f {
 740  	case driver.BlendFactorOne:
 741  		return d3d11.BLEND_ONE, d3d11.BLEND_ONE
 742  	case driver.BlendFactorOneMinusSrcAlpha:
 743  		return d3d11.BLEND_INV_SRC_ALPHA, d3d11.BLEND_INV_SRC_ALPHA
 744  	case driver.BlendFactorZero:
 745  		return d3d11.BLEND_ZERO, d3d11.BLEND_ZERO
 746  	case driver.BlendFactorDstColor:
 747  		return d3d11.BLEND_DEST_COLOR, d3d11.BLEND_DEST_ALPHA
 748  	default:
 749  		panic("unsupported blend source factor")
 750  	}
 751  }
 752  
 753  // sliceOf returns a slice from a (native) pointer.
 754  func sliceOf(ptr uintptr, cap int) []byte {
 755  	var data []byte
 756  	h := (*reflect.SliceHeader)(unsafe.Pointer(&data))
 757  	h.Data = ptr
 758  	h.Cap = cap
 759  	h.Len = cap
 760  	return data
 761  }
 762