gioui.org@v0.6.1-0.20240506124620-7a9ce51988ce/app/d3d11_windows.go (about)

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  package app
     4  
     5  import (
     6  	"fmt"
     7  	"unsafe"
     8  
     9  	"gioui.org/gpu"
    10  	"gioui.org/internal/d3d11"
    11  )
    12  
    13  type d3d11Context struct {
    14  	win *window
    15  	dev *d3d11.Device
    16  	ctx *d3d11.DeviceContext
    17  
    18  	swchain       *d3d11.IDXGISwapChain
    19  	renderTarget  *d3d11.RenderTargetView
    20  	width, height int
    21  }
    22  
    23  const debugDirectX = false
    24  
    25  func init() {
    26  	drivers = append(drivers, gpuAPI{
    27  		priority: 1,
    28  		initializer: func(w *window) (context, error) {
    29  			hwnd, _, _ := w.HWND()
    30  			var flags uint32
    31  			if debugDirectX {
    32  				flags |= d3d11.CREATE_DEVICE_DEBUG
    33  			}
    34  			dev, ctx, _, err := d3d11.CreateDevice(
    35  				d3d11.DRIVER_TYPE_HARDWARE,
    36  				flags,
    37  			)
    38  			if err != nil {
    39  				return nil, fmt.Errorf("NewContext: %v", err)
    40  			}
    41  			swchain, err := d3d11.CreateSwapChain(dev, hwnd)
    42  			if err != nil {
    43  				d3d11.IUnknownRelease(unsafe.Pointer(ctx), ctx.Vtbl.Release)
    44  				d3d11.IUnknownRelease(unsafe.Pointer(dev), dev.Vtbl.Release)
    45  				return nil, err
    46  			}
    47  			return &d3d11Context{win: w, dev: dev, ctx: ctx, swchain: swchain}, nil
    48  		},
    49  	})
    50  }
    51  
    52  func (c *d3d11Context) API() gpu.API {
    53  	return gpu.Direct3D11{Device: unsafe.Pointer(c.dev)}
    54  }
    55  
    56  func (c *d3d11Context) RenderTarget() (gpu.RenderTarget, error) {
    57  	return gpu.Direct3D11RenderTarget{
    58  		RenderTarget: unsafe.Pointer(c.renderTarget),
    59  	}, nil
    60  }
    61  
    62  func (c *d3d11Context) Present() error {
    63  	return wrapErr(c.swchain.Present(1, 0))
    64  }
    65  
    66  func wrapErr(err error) error {
    67  	if err, ok := err.(d3d11.ErrorCode); ok {
    68  		switch err.Code {
    69  		case d3d11.DXGI_STATUS_OCCLUDED:
    70  			// Ignore
    71  			return nil
    72  		case d3d11.DXGI_ERROR_DEVICE_RESET, d3d11.DXGI_ERROR_DEVICE_REMOVED, d3d11.D3DDDIERR_DEVICEREMOVED:
    73  			return gpu.ErrDeviceLost
    74  		}
    75  	}
    76  	return err
    77  }
    78  
    79  func (c *d3d11Context) Refresh() error {
    80  	var width, height int
    81  	_, width, height = c.win.HWND()
    82  	if c.renderTarget != nil && width == c.width && height == c.height {
    83  		return nil
    84  	}
    85  	c.releaseFBO()
    86  	if err := c.swchain.ResizeBuffers(0, 0, 0, d3d11.DXGI_FORMAT_UNKNOWN, 0); err != nil {
    87  		return wrapErr(err)
    88  	}
    89  	c.width = width
    90  	c.height = height
    91  
    92  	backBuffer, err := c.swchain.GetBuffer(0, &d3d11.IID_Texture2D)
    93  	if err != nil {
    94  		return err
    95  	}
    96  	texture := (*d3d11.Resource)(unsafe.Pointer(backBuffer))
    97  	renderTarget, err := c.dev.CreateRenderTargetView(texture)
    98  	d3d11.IUnknownRelease(unsafe.Pointer(backBuffer), backBuffer.Vtbl.Release)
    99  	if err != nil {
   100  		return err
   101  	}
   102  	c.renderTarget = renderTarget
   103  	return nil
   104  }
   105  
   106  func (c *d3d11Context) Lock() error {
   107  	c.ctx.OMSetRenderTargets(c.renderTarget, nil)
   108  	return nil
   109  }
   110  
   111  func (c *d3d11Context) Unlock() {}
   112  
   113  func (c *d3d11Context) Release() {
   114  	c.releaseFBO()
   115  	if c.swchain != nil {
   116  		d3d11.IUnknownRelease(unsafe.Pointer(c.swchain), c.swchain.Vtbl.Release)
   117  	}
   118  	if c.ctx != nil {
   119  		d3d11.IUnknownRelease(unsafe.Pointer(c.ctx), c.ctx.Vtbl.Release)
   120  	}
   121  	if c.dev != nil {
   122  		d3d11.IUnknownRelease(unsafe.Pointer(c.dev), c.dev.Vtbl.Release)
   123  	}
   124  	*c = d3d11Context{}
   125  	if debugDirectX {
   126  		d3d11.ReportLiveObjects()
   127  	}
   128  }
   129  
   130  func (c *d3d11Context) releaseFBO() {
   131  	if c.renderTarget != nil {
   132  		d3d11.IUnknownRelease(unsafe.Pointer(c.renderTarget), c.renderTarget.Vtbl.Release)
   133  		c.renderTarget = nil
   134  	}
   135  }