mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 11:48:55 +01:00
internal/graphicsdriver/directx: fix fence usages
Updates #2034 Updates #2138 Updates #2149
This commit is contained in:
parent
e78d888b24
commit
522660c1f9
@ -98,11 +98,8 @@ type Graphics struct {
|
|||||||
rtvDescriptorSize uint32
|
rtvDescriptorSize uint32
|
||||||
renderTargets [frameCount]*_ID3D12Resource
|
renderTargets [frameCount]*_ID3D12Resource
|
||||||
|
|
||||||
fences [frameCount]*_ID3D12Fence
|
fence *_ID3D12Fence
|
||||||
fenceValues [frameCount]uint64
|
fenceValues [frameCount]uint64
|
||||||
|
|
||||||
// fenceWaitEvent is an event.
|
|
||||||
// As all the Graphics functions work in a single thread, only one event is enough for multiple fences.
|
|
||||||
fenceWaitEvent windows.Handle
|
fenceWaitEvent windows.Handle
|
||||||
|
|
||||||
// drawCommandAllocators are command allocators for a 3D engine (DrawIndexedInstanced).
|
// drawCommandAllocators are command allocators for a 3D engine (DrawIndexedInstanced).
|
||||||
@ -162,7 +159,7 @@ func (g *Graphics) initialize() (ferr error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize not only a device but also other members like fences.
|
// Initialize not only a device but also other members like a fence.
|
||||||
// Even if initializing a device succeeds, initializing a fence might fail (#2142).
|
// Even if initializing a device succeeds, initializing a fence might fail (#2142).
|
||||||
|
|
||||||
if microsoftgdk.IsXbox() {
|
if microsoftgdk.IsXbox() {
|
||||||
@ -355,20 +352,19 @@ func (g *Graphics) initializeMembers() (ferr error) {
|
|||||||
}(i)
|
}(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create frame fences.
|
// Create a frame fence.
|
||||||
for i := 0; i < frameCount; i++ {
|
|
||||||
f, err := g.device.CreateFence(0, _D3D12_FENCE_FLAG_NONE)
|
f, err := g.device.CreateFence(0, _D3D12_FENCE_FLAG_NONE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
g.fences[i] = f
|
g.fence = f
|
||||||
defer func(i int) {
|
defer func() {
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
g.fences[i].Release()
|
g.fence.Release()
|
||||||
g.fences[i] = nil
|
g.fence = nil
|
||||||
}
|
|
||||||
}(i)
|
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
g.fenceValues[g.frameIndex]++
|
||||||
|
|
||||||
// Create command lists.
|
// Create command lists.
|
||||||
dcl, err := g.device.CreateCommandList(0, _D3D12_COMMAND_LIST_TYPE_DIRECT, g.drawCommandAllocators[0], nil)
|
dcl, err := g.device.CreateCommandList(0, _D3D12_COMMAND_LIST_TYPE_DIRECT, g.drawCommandAllocators[0], nil)
|
||||||
@ -546,14 +542,16 @@ func (g *Graphics) resizeSwapChain(width, height int) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := g.waitForCommandQueue(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g.releaseResources(g.frameIndex)
|
||||||
|
if err := g.resetCommandAllocators(g.frameIndex); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
for i := 0; i < frameCount; i++ {
|
for i := 0; i < frameCount; i++ {
|
||||||
if err := g.waitForCommandQueueForFrame(i); err != nil {
|
g.fenceValues[i] = g.fenceValues[g.frameIndex]
|
||||||
return err
|
|
||||||
}
|
|
||||||
g.releaseResources(i)
|
|
||||||
if err := g.releaseCommandAllocators(i); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, r := range g.renderTargets {
|
for _, r := range g.renderTargets {
|
||||||
@ -568,6 +566,7 @@ func (g *Graphics) resizeSwapChain(width, height int) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Reset 0 on Xbox
|
||||||
g.frameIndex = int(g.swapChain.GetCurrentBackBufferIndex())
|
g.frameIndex = int(g.swapChain.GetCurrentBackBufferIndex())
|
||||||
|
|
||||||
if err := g.drawCommandList.Reset(g.drawCommandAllocators[g.frameIndex], nil); err != nil {
|
if err := g.drawCommandList.Reset(g.drawCommandAllocators[g.frameIndex], nil); err != nil {
|
||||||
@ -667,42 +666,38 @@ func (g *Graphics) End(present bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the previous frame.
|
if err := g.moveToNextFrame(); err != nil {
|
||||||
fence := g.fences[g.frameIndex]
|
|
||||||
g.fenceValues[g.frameIndex]++
|
|
||||||
if err := g.commandQueue.Signal(fence, g.fenceValues[g.frameIndex]); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: nextIndex should be GetCurrentBackBufferIndex on desktops, right? (#2034)
|
g.releaseResources(g.frameIndex)
|
||||||
nextIndex := (g.frameIndex + 1) % frameCount
|
g.releaseVerticesAndIndices(g.frameIndex)
|
||||||
if err := g.waitForCommandQueueForFrame(nextIndex); err != nil {
|
if err := g.resetCommandAllocators(g.frameIndex); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
g.releaseResources(nextIndex)
|
|
||||||
g.releaseVerticesAndIndices(nextIndex)
|
|
||||||
if err := g.releaseCommandAllocators(nextIndex); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move to the next frame.
|
|
||||||
g.frameIndex = int(g.swapChain.GetCurrentBackBufferIndex())
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graphics) waitForCommandQueueForFrame(frameIndex int) error {
|
func (g *Graphics) moveToNextFrame() error {
|
||||||
expected := g.fenceValues[frameIndex]
|
fv := g.fenceValues[g.frameIndex]
|
||||||
actual := g.fences[frameIndex].GetCompletedValue()
|
if err := g.commandQueue.Signal(g.fence, fv); err != nil {
|
||||||
if actual < expected {
|
return err
|
||||||
if err := g.fences[frameIndex].SetEventOnCompletion(expected, g.fenceWaitEvent); err != nil {
|
}
|
||||||
|
|
||||||
|
// Update the frame index.
|
||||||
|
// TODO: The calculation might be different in Xbox.
|
||||||
|
g.frameIndex = int(g.swapChain.GetCurrentBackBufferIndex())
|
||||||
|
|
||||||
|
if g.fence.GetCompletedValue() < g.fenceValues[g.frameIndex] {
|
||||||
|
if err := g.fence.SetEventOnCompletion(fv, g.fenceWaitEvent); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := windows.WaitForSingleObject(g.fenceWaitEvent, windows.INFINITE); err != nil {
|
if _, err := windows.WaitForSingleObject(g.fenceWaitEvent, windows.INFINITE); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
g.fenceValues[g.frameIndex] = fv + 1
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -734,7 +729,7 @@ func (g *Graphics) releaseVerticesAndIndices(frameIndex int) {
|
|||||||
g.indices[frameIndex] = g.indices[frameIndex][:0]
|
g.indices[frameIndex] = g.indices[frameIndex][:0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graphics) releaseCommandAllocators(frameIndex int) error {
|
func (g *Graphics) resetCommandAllocators(frameIndex int) error {
|
||||||
if err := g.drawCommandAllocators[frameIndex].Reset(); err != nil {
|
if err := g.drawCommandAllocators[frameIndex].Reset(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -774,24 +769,17 @@ func (g *Graphics) flushCommandList(commandList *_ID3D12GraphicsCommandList) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graphics) waitForCommandQueue() error {
|
func (g *Graphics) waitForCommandQueue() error {
|
||||||
f, err := g.device.CreateFence(0, _D3D12_FENCE_FLAG_NONE)
|
fv := g.fenceValues[g.frameIndex]
|
||||||
if err != nil {
|
if err := g.commandQueue.Signal(g.fence, fv); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer f.Release()
|
if err := g.fence.SetEventOnCompletion(fv, g.fenceWaitEvent); err != nil {
|
||||||
|
|
||||||
const expected uint64 = 1
|
|
||||||
if err := g.commandQueue.Signal(f, expected); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if f.GetCompletedValue() < expected {
|
|
||||||
if err := f.SetEventOnCompletion(expected, g.fenceWaitEvent); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := windows.WaitForSingleObject(g.fenceWaitEvent, windows.INFINITE); err != nil {
|
if _, err := windows.WaitForSingleObject(g.fenceWaitEvent, windows.INFINITE); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
g.fenceValues[g.frameIndex]++
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user