~eliasnaur/gio

7024a0e6914d048cd245b1b2a4fc96df3d9538ab — Elias Naur 28 days ago 61529c2
gpu: fix depth buffer on direct3d and headless opengl

Signed-off-by: Elias Naur <mail@eliasnaur.com>
M app/headless/headless_test.go => app/headless/headless_test.go +41 -0
@@ 98,6 98,47 @@ func TestClipping(t *testing.T) {
	}
}

func TestDepth(t *testing.T) {
	w, release := newTestWindow(t)
	defer release()
	var ops op.Ops

	blue := color.RGBA{B: 0xFF, A: 0xFF}
	paint.ColorOp{Color: blue}.Add(&ops)
	paint.PaintOp{Rect: f32.Rectangle{
		Max: f32.Point{X: 50, Y: 100},
	}}.Add(&ops)
	red := color.RGBA{R: 0xFF, A: 0xFF}
	paint.ColorOp{Color: red}.Add(&ops)
	paint.PaintOp{Rect: f32.Rectangle{
		Max: f32.Point{X: 100, Y: 50},
	}}.Add(&ops)
	w.Frame(&ops)

	img, err := w.Screenshot()
	if err != nil {
		t.Fatal(err)
	}
	if *dumpImages {
		if err := saveImage("depth.png", img); err != nil {
			t.Fatal(err)
		}
	}
	tests := []struct {
		x, y  int
		color color.RGBA
	}{
		{25, 25, red},
		{75, 25, red},
		{25, 75, blue},
	}
	for _, test := range tests {
		if got := img.RGBAAt(test.x, test.y); got != test.color {
			t.Errorf("(%d,%d): got color %v, expected %v", test.x, test.y, got, test.color)
		}
	}
}

func newTestWindow(t *testing.T) (*Window, func()) {
	t.Helper()
	sz := image.Point{X: 800, Y: 600}

M app/internal/d3d11/backend_windows.go => app/internal/d3d11/backend_windows.go +45 -27
@@ 193,6 193,10 @@ func (s *SwapChain) Framebuffer(d *Device) (*Framebuffer, error) {
	if s.fbo.renderTarget != nil {
		return s.fbo, nil
	}
	desc, err := s.swchain.GetDesc()
	if err != nil {
		return nil, err
	}
	backBuffer, err := s.swchain.GetBuffer(0, &_IID_ID3D11Texture2D)
	if err != nil {
		return nil, err


@@ 203,7 207,13 @@ func (s *SwapChain) Framebuffer(d *Device) (*Framebuffer, error) {
	if err != nil {
		return nil, err
	}
	depthView, err := createDepthView(d.dev, int(desc.BufferDesc.Width), int(desc.BufferDesc.Height), 24)
	if err != nil {
		_IUnknownRelease(unsafe.Pointer(renderTarget), renderTarget.vtbl.Release)
		return nil, err
	}
	s.fbo.renderTarget = renderTarget
	s.fbo.depthView = depthView
	s.fbo.dev = d
	return s.fbo, nil
}


@@ 255,6 265,8 @@ func NewBackend(d *Device) (*Backend, error) {
		FillMode:        _D3D11_FILL_SOLID,
		DepthClipEnable: 1,
	})
	// Enable depth mask to match OpenGL.
	b.depthState.mask = true
	if err != nil {
		return nil, err
	}


@@ 359,8 371,10 @@ func (b *Backend) NewTexture(format backend.TextureFormat, width, height int, mi

func (b *Backend) CurrentFramebuffer() backend.Framebuffer {
	renderTarget := b.dev.ctx.OMGetRenderTargets()
	// Assume someone else is holding on to it.
	_IUnknownRelease(unsafe.Pointer(renderTarget), renderTarget.vtbl.Release)
	if renderTarget != nil {
		// Assume someone else is holding on to it.
		_IUnknownRelease(unsafe.Pointer(renderTarget), renderTarget.vtbl.Release)
	}
	if renderTarget == b.fbo.renderTarget {
		return b.fbo
	}


@@ 379,30 393,7 @@ func (b *Backend) NewFramebuffer(tex backend.Texture, depthBits int) (backend.Fr
	}
	fbo := &Framebuffer{dev: b.dev, format: d3dtex.format, resource: resource, renderTarget: renderTarget}
	if depthBits > 0 {
		depthTex, err := b.dev.dev.CreateTexture2D(&_D3D11_TEXTURE2D_DESC{
			Width:     uint32(d3dtex.width),
			Height:    uint32(d3dtex.height),
			MipLevels: 1,
			ArraySize: 1,
			Format:    _DXGI_FORMAT_D24_UNORM_S8_UINT,
			SampleDesc: _DXGI_SAMPLE_DESC{
				Count:   1,
				Quality: 0,
			},
			BindFlags: _D3D11_BIND_DEPTH_STENCIL,
		})
		if err != nil {
			_IUnknownRelease(unsafe.Pointer(renderTarget), renderTarget.vtbl.Release)
			return nil, err
		}
		depthView, err := b.dev.dev.CreateDepthStencilViewTEX2D(
			(*_ID3D11Resource)(unsafe.Pointer(depthTex)),
			&_D3D11_DEPTH_STENCIL_VIEW_DESC_TEX2D{
				Format:        _DXGI_FORMAT_D24_UNORM_S8_UINT,
				ViewDimension: _D3D11_DSV_DIMENSION_TEXTURE2D,
			},
		)
		_IUnknownRelease(unsafe.Pointer(depthTex), depthTex.vtbl.Release)
		depthView, err := createDepthView(b.dev.dev, d3dtex.width, d3dtex.height, depthBits)
		if err != nil {
			_IUnknownRelease(unsafe.Pointer(renderTarget), renderTarget.vtbl.Release)
			return nil, err


@@ 412,6 403,33 @@ func (b *Backend) NewFramebuffer(tex backend.Texture, depthBits int) (backend.Fr
	return fbo, nil
}

func createDepthView(d *_ID3D11Device, width, height, depthBits int) (*_ID3D11DepthStencilView, error) {
	depthTex, err := d.CreateTexture2D(&_D3D11_TEXTURE2D_DESC{
		Width:     uint32(width),
		Height:    uint32(height),
		MipLevels: 1,
		ArraySize: 1,
		Format:    _DXGI_FORMAT_D24_UNORM_S8_UINT,
		SampleDesc: _DXGI_SAMPLE_DESC{
			Count:   1,
			Quality: 0,
		},
		BindFlags: _D3D11_BIND_DEPTH_STENCIL,
	})
	if err != nil {
		return nil, err
	}
	depthView, err := d.CreateDepthStencilViewTEX2D(
		(*_ID3D11Resource)(unsafe.Pointer(depthTex)),
		&_D3D11_DEPTH_STENCIL_VIEW_DESC_TEX2D{
			Format:        _DXGI_FORMAT_D24_UNORM_S8_UINT,
			ViewDimension: _D3D11_DSV_DIMENSION_TEXTURE2D,
		},
	)
	_IUnknownRelease(unsafe.Pointer(depthTex), depthTex.vtbl.Release)
	return depthView, err
}

func (b *Backend) NewInputLayout(vertexShader backend.ShaderSources, layout []backend.InputDesc) (backend.InputLayout, error) {
	if len(vertexShader.Inputs) != len(layout) {
		return nil, fmt.Errorf("NewInputLayout: got %d inputs, expected %d", len(layout), len(vertexShader.Inputs))


@@ 583,7 601,7 @@ func (b *Backend) prepareDraw(mode backend.DrawMode) {
		if b.depthState.enable {
			desc.DepthEnable = 1
		}
		if !b.depthState.mask {
		if b.depthState.mask {
			desc.DepthWriteMask = _D3D11_DEPTH_WRITE_MASK_ALL
		}
		switch b.depthState.fn {

M app/internal/d3d11/d3d11_windows.go => app/internal/d3d11/d3d11_windows.go +15 -0
@@ 912,6 912,21 @@ func (d *_ID3D11Device) CreateDepthStencilState(desc *_D3D11_DEPTH_STENCIL_DESC)
	return state, nil
}

func (s *_IDXGISwapChain) GetDesc() (_DXGI_SWAP_CHAIN_DESC, error) {
	var desc _DXGI_SWAP_CHAIN_DESC
	r, _, _ := syscall.Syscall(
		s.vtbl.GetDesc,
		2,
		uintptr(unsafe.Pointer(s)),
		uintptr(unsafe.Pointer(&desc)),
		0,
	)
	if r != 0 {
		return _DXGI_SWAP_CHAIN_DESC{}, ErrorCode{Name: "IDXGISwapChainGetDesc", Code: uint32(r)}
	}
	return desc, nil
}

func (s *_IDXGISwapChain) ResizeBuffers(buffers, width, height, newFormat, flags uint32) error {
	r, _, _ := syscall.Syscall6(
		s.vtbl.ResizeBuffers,

M gpu/gl/backend.go => gpu/gl/backend.go +1 -0
@@ 194,6 194,7 @@ func (b *Backend) NewFramebuffer(tex backend.Texture, depthBits int) (backend.Fr
		depthBuf := b.funcs.CreateRenderbuffer()
		b.funcs.BindRenderbuffer(RENDERBUFFER, depthBuf)
		b.funcs.RenderbufferStorage(RENDERBUFFER, size, gltex.width, gltex.height)
		b.funcs.FramebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT, RENDERBUFFER, depthBuf)
		fbo.depthBuf = depthBuf
		fbo.hasDepth = true
		if err := glErr(b.funcs); err != nil {

M gpu/gl/gl.go => gpu/gl/gl.go +1 -0
@@ 129,6 129,7 @@ type Functions interface {
	EnableVertexAttribArray(a Attrib)
	EndQuery(target Enum)
	FramebufferTexture2D(target, attachment, texTarget Enum, t Texture, level int)
	FramebufferRenderbuffer(target, attachment, renderbuffertarget Enum, renderbuffer Renderbuffer)
	GetBinding(pname Enum) Object
	GetError() Enum
	GetInteger(pname Enum) int