github.com/cybriq/giocore@v0.0.7-0.20210703034601-cfb9cb5f3900/app/internal/wm/d3d11_windows.go (about)

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  package wm
     4  
     5  import (
     6  	"fmt"
     7  	"unsafe"
     8  
     9  	"github.com/cybriq/giocore/gpu"
    10  	"github.com/cybriq/giocore/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  	depthView     *d3d11.DepthStencilView
    21  	width, height int
    22  }
    23  
    24  const debug = false
    25  
    26  func init() {
    27  	drivers = append(drivers, gpuAPI{
    28  		priority: 1,
    29  		initializer: func(w *window) (Context, error) {
    30  			hwnd, _, _ := w.HWND()
    31  			var flags uint32
    32  			if debug {
    33  				flags |= d3d11.CREATE_DEVICE_DEBUG
    34  			}
    35  			dev, ctx, _, err := d3d11.CreateDevice(
    36  				d3d11.DRIVER_TYPE_HARDWARE,
    37  				flags,
    38  			)
    39  			if err != nil {
    40  				return nil, fmt.Errorf("NewContext: %v", err)
    41  			}
    42  			swchain, err := d3d11.CreateSwapChain(dev, hwnd)
    43  			if err != nil {
    44  				d3d11.IUnknownRelease(unsafe.Pointer(ctx), ctx.Vtbl.Release)
    45  				d3d11.IUnknownRelease(unsafe.Pointer(dev), dev.Vtbl.Release)
    46  				return nil, err
    47  			}
    48  			return &d3d11Context{win: w, dev: dev, ctx: ctx, swchain: swchain}, nil
    49  		},
    50  	})
    51  }
    52  
    53  func (c *d3d11Context) API() gpu.API {
    54  	return gpu.Direct3D11{Device: unsafe.Pointer(c.dev)}
    55  }
    56  
    57  func (c *d3d11Context) Present() error {
    58  	err := c.swchain.Present(1, 0)
    59  	if err == nil {
    60  		return nil
    61  	}
    62  	if err, ok := err.(d3d11.ErrorCode); ok {
    63  		switch err.Code {
    64  		case d3d11.DXGI_STATUS_OCCLUDED:
    65  			// Ignore
    66  			return nil
    67  		case d3d11.DXGI_ERROR_DEVICE_RESET, d3d11.DXGI_ERROR_DEVICE_REMOVED, d3d11.D3DDDIERR_DEVICEREMOVED:
    68  			return ErrDeviceLost
    69  		}
    70  	}
    71  	return err
    72  }
    73  
    74  func (c *d3d11Context) Refresh() error {
    75  	return nil
    76  }
    77  
    78  func (c *d3d11Context) MakeCurrent() error {
    79  	var width, height int
    80  	c.win.w.Run(func() {
    81  		_, width, height = c.win.HWND()
    82  	})
    83  	if c.renderTarget != nil && width == c.width && height == c.height {
    84  		c.ctx.OMSetRenderTargets(c.renderTarget, c.depthView)
    85  		return nil
    86  	}
    87  	c.releaseFBO()
    88  	if err := c.swchain.ResizeBuffers(0, 0, 0, d3d11.DXGI_FORMAT_UNKNOWN, 0); err != nil {
    89  		return err
    90  	}
    91  	c.width = width
    92  	c.height = height
    93  
    94  	desc, err := c.swchain.GetDesc()
    95  	if err != nil {
    96  		return err
    97  	}
    98  	backBuffer, err := c.swchain.GetBuffer(0, &d3d11.IID_Texture2D)
    99  	if err != nil {
   100  		return err
   101  	}
   102  	texture := (*d3d11.Resource)(unsafe.Pointer(backBuffer))
   103  	renderTarget, err := c.dev.CreateRenderTargetView(texture)
   104  	d3d11.IUnknownRelease(unsafe.Pointer(backBuffer), backBuffer.Vtbl.Release)
   105  	if err != nil {
   106  		return err
   107  	}
   108  	depthView, err := d3d11.CreateDepthView(c.dev, int(desc.BufferDesc.Width), int(desc.BufferDesc.Height), 24)
   109  	if err != nil {
   110  		d3d11.IUnknownRelease(unsafe.Pointer(renderTarget), renderTarget.Vtbl.Release)
   111  		return err
   112  	}
   113  	c.renderTarget = renderTarget
   114  	c.depthView = depthView
   115  
   116  	c.ctx.OMSetRenderTargets(c.renderTarget, c.depthView)
   117  	return nil
   118  }
   119  
   120  func (c *d3d11Context) Lock() {}
   121  
   122  func (c *d3d11Context) Unlock() {}
   123  
   124  func (c *d3d11Context) Release() {
   125  	c.releaseFBO()
   126  	if c.swchain != nil {
   127  		d3d11.IUnknownRelease(unsafe.Pointer(c.swchain), c.swchain.Vtbl.Release)
   128  	}
   129  	if c.ctx != nil {
   130  		d3d11.IUnknownRelease(unsafe.Pointer(c.ctx), c.ctx.Vtbl.Release)
   131  	}
   132  	if c.dev != nil {
   133  		d3d11.IUnknownRelease(unsafe.Pointer(c.dev), c.dev.Vtbl.Release)
   134  	}
   135  	*c = d3d11Context{}
   136  }
   137  
   138  func (c *d3d11Context) releaseFBO() {
   139  	if c.depthView != nil {
   140  		d3d11.IUnknownRelease(unsafe.Pointer(c.depthView), c.depthView.Vtbl.Release)
   141  		c.depthView = nil
   142  	}
   143  	if c.renderTarget != nil {
   144  		d3d11.IUnknownRelease(unsafe.Pointer(c.renderTarget), c.renderTarget.Vtbl.Release)
   145  		c.renderTarget = nil
   146  	}
   147  }