internal/graphicsdriver/directx: reduce memory usages for writing pixels

Updates #2294
Updates #2582
This commit is contained in:
Hajime Hoshi 2023-03-01 00:11:34 +09:00
parent 264f0bad42
commit a5a5de2f3f

View File

@ -1005,6 +1005,10 @@ func (g *Graphics) flushCommandList(commandList *_ID3D12GraphicsCommandList) err
if err := commandList.Reset(g.copyCommandAllocators[g.frameIndex], nil); err != nil { if err := commandList.Reset(g.copyCommandAllocators[g.frameIndex], nil); err != nil {
return err return err
} }
for _, img := range g.images {
img.releaseUploadingStagingBuffers()
}
} }
return nil return nil
@ -1118,20 +1122,13 @@ func (g *Graphics) NewImage(width, height int) (graphicsdriver.Image, error) {
return nil, err return nil, err
} }
layouts, _, _, totalBytes := g.device.GetCopyableFootprints(&desc, 0, 1, 0)
if totalBytes == ^uint64(0) {
return nil, fmt.Errorf("directx: GetCopyableFootprints returned an invalid total bytes")
}
i := &Image{ i := &Image{
graphics: g, graphics: g,
id: g.genNextImageID(), id: g.genNextImageID(),
width: width, width: width,
height: height, height: height,
texture: t, texture: t,
states: [frameCount]_D3D12_RESOURCE_STATES{state}, states: [frameCount]_D3D12_RESOURCE_STATES{state},
layouts: layouts,
totalBytes: totalBytes,
} }
g.addImage(i) g.addImage(i)
return i, nil return i, nil
@ -1329,14 +1326,13 @@ type Image struct {
height int height int
screen bool screen bool
states [frameCount]_D3D12_RESOURCE_STATES states [frameCount]_D3D12_RESOURCE_STATES
texture *_ID3D12Resource texture *_ID3D12Resource
stencil *_ID3D12Resource stencil *_ID3D12Resource
layouts _D3D12_PLACED_SUBRESOURCE_FOOTPRINT rtvDescriptorHeap *_ID3D12DescriptorHeap
totalBytes uint64 dsvDescriptorHeap *_ID3D12DescriptorHeap
uploadingStagingBuffer *_ID3D12Resource
rtvDescriptorHeap *_ID3D12DescriptorHeap uploadingStagingBuffers []*_ID3D12Resource
dsvDescriptorHeap *_ID3D12DescriptorHeap
} }
func (i *Image) ID() graphicsdriver.ImageID { func (i *Image) ID() graphicsdriver.ImageID {
@ -1357,10 +1353,6 @@ func (i *Image) disposeImpl() {
i.rtvDescriptorHeap.Release() i.rtvDescriptorHeap.Release()
i.rtvDescriptorHeap = nil i.rtvDescriptorHeap = nil
} }
if i.uploadingStagingBuffer != nil {
i.uploadingStagingBuffer.Release()
i.uploadingStagingBuffer = nil
}
if i.stencil != nil { if i.stencil != nil {
i.stencil.Release() i.stencil.Release()
i.stencil = nil i.stencil = nil
@ -1375,18 +1367,6 @@ func (*Image) IsInvalidated() bool {
return false return false
} }
func (i *Image) ensureUploadingStagingBuffer() error {
if i.uploadingStagingBuffer != nil {
return nil
}
var err error
i.uploadingStagingBuffer, err = createBuffer(i.graphics.device, i.totalBytes, _D3D12_HEAP_TYPE_UPLOAD)
if err != nil {
return err
}
return nil
}
func (i *Image) ReadPixels(buf []byte, x, y, width, height int) error { func (i *Image) ReadPixels(buf []byte, x, y, width, height int) error {
if i.screen { if i.screen {
return errors.New("directx: Pixels cannot be called on the screen") return errors.New("directx: Pixels cannot be called on the screen")
@ -1473,25 +1453,62 @@ func (i *Image) WritePixels(args []*graphicsdriver.WritePixelsArgs) error {
return err return err
} }
if err := i.ensureUploadingStagingBuffer(); err != nil { minX := i.width
minY := i.height
maxX := 0
maxY := 0
for _, a := range args {
if minX > a.X {
minX = a.X
}
if minY > a.Y {
minY = a.Y
}
if maxX < a.X+a.Width {
maxX = a.X + a.Width
}
if maxY < a.Y+a.Height {
maxY = a.Y + a.Height
}
}
desc := _D3D12_RESOURCE_DESC{
Dimension: _D3D12_RESOURCE_DIMENSION_TEXTURE2D,
Alignment: 0,
Width: uint64(maxX - minX),
Height: uint32(maxY - minY),
DepthOrArraySize: 1,
MipLevels: 0,
Format: _DXGI_FORMAT_R8G8B8A8_UNORM,
SampleDesc: _DXGI_SAMPLE_DESC{
Count: 1,
Quality: 0,
},
Layout: _D3D12_TEXTURE_LAYOUT_UNKNOWN,
Flags: _D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET,
}
layouts, _, _, totalBytes := i.graphics.device.GetCopyableFootprints(&desc, 0, 1, 0)
uploadingStagingBuffer, err := createBuffer(i.graphics.device, totalBytes, _D3D12_HEAP_TYPE_UPLOAD)
if err != nil {
return err return err
} }
i.uploadingStagingBuffers = append(i.uploadingStagingBuffers, uploadingStagingBuffer)
if rb, ok := i.transiteState(_D3D12_RESOURCE_STATE_COPY_DEST); ok { if rb, ok := i.transiteState(_D3D12_RESOURCE_STATE_COPY_DEST); ok {
i.graphics.copyCommandList.ResourceBarrier([]_D3D12_RESOURCE_BARRIER_Transition{rb}) i.graphics.copyCommandList.ResourceBarrier([]_D3D12_RESOURCE_BARRIER_Transition{rb})
} }
m, err := i.uploadingStagingBuffer.Map(0, &_D3D12_RANGE{0, 0}) m, err := uploadingStagingBuffer.Map(0, &_D3D12_RANGE{0, 0})
if err != nil { if err != nil {
return err return err
} }
i.graphics.needFlushCopyCommandList = true i.graphics.needFlushCopyCommandList = true
srcBytes := unsafe.Slice((*byte)(unsafe.Pointer(m)), i.totalBytes) srcBytes := unsafe.Slice((*byte)(unsafe.Pointer(m)), totalBytes)
for _, a := range args { for _, a := range args {
for j := 0; j < a.Height; j++ { for j := 0; j < a.Height; j++ {
copy(srcBytes[(a.Y+j)*int(i.layouts.Footprint.RowPitch)+a.X*4:], a.Pixels[j*a.Width*4:(j+1)*a.Width*4]) copy(srcBytes[((a.Y-minY)+j)*int(layouts.Footprint.RowPitch)+(a.X-minX)*4:], a.Pixels[j*a.Width*4:(j+1)*a.Width*4])
} }
} }
@ -1502,22 +1519,22 @@ func (i *Image) WritePixels(args []*graphicsdriver.WritePixelsArgs) error {
SubresourceIndex: 0, SubresourceIndex: 0,
} }
src := _D3D12_TEXTURE_COPY_LOCATION_PlacedFootPrint{ src := _D3D12_TEXTURE_COPY_LOCATION_PlacedFootPrint{
pResource: i.uploadingStagingBuffer, pResource: uploadingStagingBuffer,
Type: _D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, Type: _D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
PlacedFootprint: i.layouts, PlacedFootprint: layouts,
} }
i.graphics.copyCommandList.CopyTextureRegion_SubresourceIndex_PlacedFootPrint( i.graphics.copyCommandList.CopyTextureRegion_SubresourceIndex_PlacedFootPrint(
&dst, uint32(a.X), uint32(a.Y), 0, &src, &_D3D12_BOX{ &dst, uint32(a.X), uint32(a.Y), 0, &src, &_D3D12_BOX{
left: uint32(a.X), left: uint32(a.X - minX),
top: uint32(a.Y), top: uint32(a.Y - minY),
front: 0, front: 0,
right: uint32(a.X + a.Width), right: uint32(a.X - minX + a.Width),
bottom: uint32(a.Y + a.Height), bottom: uint32(a.Y - minY + a.Height),
back: 1, back: 1,
}) })
} }
i.uploadingStagingBuffer.Unmap(0, nil) uploadingStagingBuffer.Unmap(0, nil)
return nil return nil
} }
@ -1699,6 +1716,14 @@ func (i *Image) ensureDepthStencilView(device *_ID3D12Device) error {
return nil return nil
} }
func (i *Image) releaseUploadingStagingBuffers() {
for idx, buf := range i.uploadingStagingBuffers {
buf.Release()
i.uploadingStagingBuffers[idx] = nil
}
i.uploadingStagingBuffers = i.uploadingStagingBuffers[:0]
}
type stencilMode int type stencilMode int
const ( const (