github.com/cybriq/giocore@v0.0.7-0.20210703034601-cfb9cb5f3900/gpu/internal/d3d11/d3d11_windows.go (about) 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/cybriq/giocore/gpu/internal/driver" 16 "github.com/cybriq/giocore/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(clear bool, viewport image.Point) 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 }