d3d11_windows.go 24 KB

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