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