diff --git a/internal/graphicsdriver/directx/api_windows.go b/internal/graphicsdriver/directx/api_windows.go index 473d7b6b3..012069e05 100644 --- a/internal/graphicsdriver/directx/api_windows.go +++ b/internal/graphicsdriver/directx/api_windows.go @@ -59,7 +59,6 @@ const ( _D3D12_SDK_VERSION = (_D3D12_SDK_VERSION_MAJOR << 16) | _D3D12_SDK_VERSION_MINOR _D3D12_SDK_VERSION_MAJOR = 2 _D3D12_SDK_VERSION_MINOR = 4 - _D3D12_TEXTURE_DATA_PITCH_ALIGNMENT = 256 _D3D12XBOX_DEFAULT_SIZE_BYTES = 0xffffffff ) diff --git a/internal/graphicsdriver/directx/graphics_windows.go b/internal/graphicsdriver/directx/graphics_windows.go index da78081e7..6759b47fd 100644 --- a/internal/graphicsdriver/directx/graphics_windows.go +++ b/internal/graphicsdriver/directx/graphics_windows.go @@ -1075,13 +1075,20 @@ func (g *Graphics) NewImage(width, height int) (graphicsdriver.Image, error) { 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{ - graphics: g, - id: g.genNextImageID(), - width: width, - height: height, - texture: t, - states: [frameCount]_D3D12_RESOURCE_STATES{state}, + graphics: g, + id: g.genNextImageID(), + width: width, + height: height, + texture: t, + states: [frameCount]_D3D12_RESOURCE_STATES{state}, + layouts: layouts, + totalBytes: totalBytes, } g.addImage(i) return i, nil @@ -1453,6 +1460,8 @@ type Image struct { states [frameCount]_D3D12_RESOURCE_STATES texture *_ID3D12Resource stencil *_ID3D12Resource + layouts _D3D12_PLACED_SUBRESOURCE_FOOTPRINT + totalBytes uint64 uploadingStagingBuffer *_ID3D12Resource readingStagingBuffer *_ID3D12Resource rtvDescriptorHeap *_ID3D12DescriptorHeap @@ -1499,42 +1508,28 @@ func (*Image) IsInvalidated() bool { return false } -func (i *Image) ensureUploadingStagingBuffer() (*_ID3D12Resource, error) { - // Unlike readingStagingBuffer, uploadingStagingBuffer's lifetime is not determined and cannot recreate easily. - // Then, keep using the same uploadingStagingBuffer for one image. - +func (i *Image) ensureUploadingStagingBuffer() error { if i.uploadingStagingBuffer != nil { - return i.uploadingStagingBuffer, nil + return nil } - - iw, ih := graphics.InternalImageSize(i.width), graphics.InternalImageSize(i.height) - alignedWidth := align(4 * iw) - size := alignedWidth * ih - - usb, err := createBuffer(i.graphics.device, uint64(size), _D3D12_HEAP_TYPE_UPLOAD) + var err error + i.uploadingStagingBuffer, err = createBuffer(i.graphics.device, i.totalBytes, _D3D12_HEAP_TYPE_UPLOAD) if err != nil { - return nil, err + return err } - i.uploadingStagingBuffer = usb - return usb, nil + return nil } -func (i *Image) ensureReadingStagingBuffer(size uint64) (*_ID3D12Resource, error) { - if i.readingStagingBuffer != nil && i.readingStagingBuffer.GetDesc().Width < size { - i.readingStagingBuffer.Release() - i.readingStagingBuffer = nil - } - +func (i *Image) ensureReadingStagingBuffer() error { if i.readingStagingBuffer != nil { - return i.readingStagingBuffer, nil + return nil } - - rsb, err := createBuffer(i.graphics.device, size, _D3D12_HEAP_TYPE_READBACK) + var err error + i.readingStagingBuffer, err = createBuffer(i.graphics.device, i.totalBytes, _D3D12_HEAP_TYPE_READBACK) if err != nil { - return nil, err + return err } - i.readingStagingBuffer = rsb - return rsb, nil + return nil } func (i *Image) ReadPixels(buf []byte, x, y, width, height int) error { @@ -1546,9 +1541,7 @@ func (i *Image) ReadPixels(buf []byte, x, y, width, height int) error { return err } - alignedWidth := align(4 * width) - rsb, err := i.ensureReadingStagingBuffer(uint64(alignedWidth * height)) - if err != nil { + if err := i.ensureReadingStagingBuffer(); err != nil { return err } @@ -1556,24 +1549,15 @@ func (i *Image) ReadPixels(buf []byte, x, y, width, height int) error { i.graphics.copyCommandList.ResourceBarrier([]_D3D12_RESOURCE_BARRIER_Transition{rb}) } - m, err := rsb.Map(0, &_D3D12_RANGE{0, 0}) + m, err := i.readingStagingBuffer.Map(0, &_D3D12_RANGE{0, 0}) if err != nil { return err } dst := _D3D12_TEXTURE_COPY_LOCATION_PlacedFootPrint{ - pResource: rsb, - Type: _D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, - PlacedFootprint: _D3D12_PLACED_SUBRESOURCE_FOOTPRINT{ - Offset: 0, - Footprint: _D3D12_SUBRESOURCE_FOOTPRINT{ - Format: _DXGI_FORMAT_R8G8B8A8_UNORM, - Width: uint32(width), - Height: uint32(height), - Depth: 1, - RowPitch: uint32(alignedWidth), - }, - }, + pResource: i.readingStagingBuffer, + Type: _D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, + PlacedFootprint: i.layouts, } src := _D3D12_TEXTURE_COPY_LOCATION_SubresourceIndex{ pResource: i.texture, @@ -1598,14 +1582,14 @@ func (i *Image) ReadPixels(buf []byte, x, y, width, height int) error { var dstBytes []byte h := (*reflect.SliceHeader)(unsafe.Pointer(&dstBytes)) h.Data = uintptr(m) - h.Len = alignedWidth * height - h.Cap = alignedWidth * height + h.Len = int(i.totalBytes) + h.Cap = int(i.totalBytes) for j := 0; j < height; j++ { - copy(buf[j*width*4:(j+1)*width*4], dstBytes[j*alignedWidth:]) + copy(buf[j*width*4:(j+1)*width*4], dstBytes[j*int(i.layouts.Footprint.RowPitch):]) } - rsb.Unmap(0, nil) + i.readingStagingBuffer.Unmap(0, nil) return nil } @@ -1619,8 +1603,7 @@ func (i *Image) WritePixels(args []*graphicsdriver.WritePixelsArgs) error { return err } - usb, err := i.ensureUploadingStagingBuffer() - if err != nil { + if err := i.ensureUploadingStagingBuffer(); err != nil { return err } @@ -1628,46 +1611,32 @@ func (i *Image) WritePixels(args []*graphicsdriver.WritePixelsArgs) error { i.graphics.copyCommandList.ResourceBarrier([]_D3D12_RESOURCE_BARRIER_Transition{rb}) } - m, err := usb.Map(0, &_D3D12_RANGE{0, 0}) + m, err := i.uploadingStagingBuffer.Map(0, &_D3D12_RANGE{0, 0}) if err != nil { return err } i.graphics.needFlushCopyCommandList = true - iw, ih := graphics.InternalImageSize(i.width), graphics.InternalImageSize(i.height) - alignedWidth := align(4 * iw) - var srcBytes []byte h := (*reflect.SliceHeader)(unsafe.Pointer(&srcBytes)) h.Data = uintptr(m) - h.Len = alignedWidth * ih - h.Cap = alignedWidth * ih + h.Len = int(i.totalBytes) + h.Cap = int(i.totalBytes) for _, a := range args { for j := 0; j < a.Height; j++ { - copy(srcBytes[(a.Y+j)*alignedWidth+a.X*4:], a.Pixels[j*a.Width*4:(j+1)*a.Width*4]) + copy(srcBytes[(a.Y+j)*int(i.layouts.Footprint.RowPitch)+a.X*4:], a.Pixels[j*a.Width*4:(j+1)*a.Width*4]) } - } - for _, a := range args { dst := _D3D12_TEXTURE_COPY_LOCATION_SubresourceIndex{ pResource: i.texture, Type: _D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, SubresourceIndex: 0, } src := _D3D12_TEXTURE_COPY_LOCATION_PlacedFootPrint{ - pResource: usb, - Type: _D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, - PlacedFootprint: _D3D12_PLACED_SUBRESOURCE_FOOTPRINT{ - Offset: 0, - Footprint: _D3D12_SUBRESOURCE_FOOTPRINT{ - Format: _DXGI_FORMAT_R8G8B8A8_UNORM, - Width: uint32(iw), - Height: uint32(ih), - Depth: 1, - RowPitch: uint32(alignedWidth), - }, - }, + pResource: i.uploadingStagingBuffer, + Type: _D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, + PlacedFootprint: i.layouts, } i.graphics.copyCommandList.CopyTextureRegion_SubresourceIndex_PlacedFootPrint( &dst, uint32(a.X), uint32(a.Y), 0, &src, &_D3D12_BOX{ @@ -1680,7 +1649,7 @@ func (i *Image) WritePixels(args []*graphicsdriver.WritePixelsArgs) error { }) } - usb.Unmap(0, nil) + i.uploadingStagingBuffer.Unmap(0, nil) return nil } @@ -2046,7 +2015,3 @@ func (s *Shader) uniformsToFloat32s(uniforms [][]float32) []float32 { } return fs } - -func align(x int) int { - return (((x - 1) / _D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) + 1) * _D3D12_TEXTURE_DATA_PITCH_ALIGNMENT -}