blob: 55de577a8b3f4d4ca9ec68f2f32dcc6166e9b1b1 [file] [log] [blame]
// Copyright 2017 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_native/d3d12/TextureCopySplitter.h"
#include "common/Assert.h"
#include "dawn_native/d3d12/d3d12_platform.h"
namespace backend { namespace d3d12 {
namespace {
void ComputeTexelOffsets(uint32_t offset,
uint32_t rowPitch,
uint32_t slicePitch,
uint32_t texelSize,
uint32_t* texelOffsetX,
uint32_t* texelOffsetY,
uint32_t* texelOffsetZ) {
uint32_t byteOffsetX = offset % rowPitch;
offset -= byteOffsetX;
uint32_t byteOffsetY = offset % slicePitch;
uint32_t byteOffsetZ = offset - byteOffsetY;
*texelOffsetX = byteOffsetX / texelSize;
*texelOffsetY = byteOffsetY / rowPitch;
*texelOffsetZ = byteOffsetZ / slicePitch;
}
} // namespace
TextureCopySplit ComputeTextureCopySplit(uint32_t x,
uint32_t y,
uint32_t z,
uint32_t width,
uint32_t height,
uint32_t depth,
uint32_t texelSize,
uint32_t offset,
uint32_t rowPitch) {
TextureCopySplit copy;
if (z != 0 || depth > 1) {
// TODO(enga@google.com): Handle 3D / 2D arrays
ASSERT(false);
return copy;
}
ASSERT(rowPitch % texelSize == 0);
uint32_t alignedOffset = offset & ~(D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT - 1);
copy.offset = alignedOffset;
if (offset == alignedOffset) {
copy.count = 1;
copy.copies[0].textureOffset.x = x;
copy.copies[0].textureOffset.y = y;
copy.copies[0].textureOffset.z = z;
copy.copies[0].copySize.width = width;
copy.copies[0].copySize.height = height;
copy.copies[0].copySize.depth = depth;
copy.copies[0].bufferOffset.x = 0;
copy.copies[0].bufferOffset.y = 0;
copy.copies[0].bufferOffset.z = 0;
copy.copies[0].bufferSize.width = width;
copy.copies[0].bufferSize.height = height;
copy.copies[0].bufferSize.depth = depth;
// Return early. There is only one copy needed because the offset is already 512-byte
// aligned
return copy;
}
ASSERT(alignedOffset < offset);
uint32_t texelOffsetX, texelOffsetY, texelOffsetZ;
ComputeTexelOffsets(offset - alignedOffset, rowPitch, rowPitch * height, texelSize,
&texelOffsetX, &texelOffsetY, &texelOffsetZ);
uint32_t rowPitchInTexels = rowPitch / texelSize;
if (width + texelOffsetX <= rowPitchInTexels) {
// The region's rows fit inside the row pitch. In this case, extend the width of the
// PlacedFootprint and copy the buffer with an offset location
// |<--------------- row pitch --------------->|
//
// |-------------------------------------------|
// | |
// | +++++++++++++++++~~~~~~~~~|
// |~~~~~~~~~~~~~~~~~+++++++++++++++++~~~~~~~~~|
// |~~~~~~~~~~~~~~~~~+++++++++++++++++~~~~~~~~~|
// |~~~~~~~~~~~~~~~~~+++++++++++++++++~~~~~~~~~|
// |~~~~~~~~~~~~~~~~~+++++++++++++++++ |
// |-------------------------------------------|
// Copy 0:
// |----------------------------------|
// | |
// | +++++++++++++++++|
// |~~~~~~~~~~~~~~~~~+++++++++++++++++|
// |~~~~~~~~~~~~~~~~~+++++++++++++++++|
// |~~~~~~~~~~~~~~~~~+++++++++++++++++|
// |~~~~~~~~~~~~~~~~~+++++++++++++++++|
// |----------------------------------|
copy.count = 1;
copy.copies[0].textureOffset.x = x;
copy.copies[0].textureOffset.y = y;
copy.copies[0].textureOffset.z = z;
copy.copies[0].copySize.width = width;
copy.copies[0].copySize.height = height;
copy.copies[0].copySize.depth = depth;
copy.copies[0].bufferOffset.x = texelOffsetX;
copy.copies[0].bufferOffset.y = texelOffsetY;
copy.copies[0].bufferOffset.z = texelOffsetZ;
copy.copies[0].bufferSize.width = width + texelOffsetX;
copy.copies[0].bufferSize.height = height + texelOffsetY;
copy.copies[0].bufferSize.depth = depth + texelOffsetZ;
return copy;
}
// The region's rows straddle the row pitch. Split the copy into two copies
// |<--------------- row pitch --------------->|
//
// |-------------------------------------------|
// | |
// | ++++++++|
// |+++++++++~~~~~~~~~~~~~~~~~~~~~~~~~~++++++++|
// |+++++++++~~~~~~~~~~~~~~~~~~~~~~~~~~++++++++|
// |+++++++++~~~~~~~~~~~~~~~~~~~~~~~~~~++++++++|
// |+++++++++~~~~~~~~~~~~~~~~~~~~~~~~~~++++++++|
// |+++++++++ |
// |-------------------------------------------|
// Copy 0:
// |-------------------------------------------|
// | |
// | ++++++++|
// |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++++++++|
// |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++++++++|
// |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++++++++|
// |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++++++++|
// |-------------------------------------------|
// Copy 1:
// |---------|
// | |
// | |
// |+++++++++|
// |+++++++++|
// |+++++++++|
// |+++++++++|
// |+++++++++|
// |---------|
copy.count = 2;
copy.copies[0].textureOffset.x = x;
copy.copies[0].textureOffset.y = y;
copy.copies[0].textureOffset.z = z;
ASSERT(rowPitchInTexels > texelOffsetX);
copy.copies[0].copySize.width = rowPitchInTexels - texelOffsetX;
copy.copies[0].copySize.height = height;
copy.copies[0].copySize.depth = depth;
copy.copies[0].bufferOffset.x = texelOffsetX;
copy.copies[0].bufferOffset.y = texelOffsetY;
copy.copies[0].bufferOffset.z = texelOffsetZ;
copy.copies[0].bufferSize.width = rowPitchInTexels;
copy.copies[0].bufferSize.height = height + texelOffsetY;
copy.copies[0].bufferSize.depth = depth + texelOffsetZ;
copy.copies[1].textureOffset.x = x + copy.copies[0].copySize.width;
copy.copies[1].textureOffset.y = y;
copy.copies[1].textureOffset.z = z;
ASSERT(width > copy.copies[0].copySize.width);
copy.copies[1].copySize.width = width - copy.copies[0].copySize.width;
copy.copies[1].copySize.height = height;
copy.copies[1].copySize.depth = depth;
copy.copies[1].bufferOffset.x = 0;
copy.copies[1].bufferOffset.y = texelOffsetY + 1;
copy.copies[1].bufferOffset.z = texelOffsetZ;
copy.copies[1].bufferSize.width = copy.copies[1].copySize.width;
copy.copies[1].bufferSize.height = height + texelOffsetY + 1;
copy.copies[1].bufferSize.depth = depth + texelOffsetZ;
return copy;
}
}} // namespace backend::d3d12