Support 2D array texture copying on D3D12, Metal and OpenGL
This patch implements the creation of 2D array textures and copying between a buffer and a layer of a 2D array texture on D3D12, Metal and OpenGL back-ends. TEST=dawn_end2end_tests
This commit is contained in:
parent
d8597b2e1f
commit
4ccf4e3fdd
|
@ -333,7 +333,9 @@ namespace dawn_native { namespace d3d12 {
|
|||
D3D12_TEXTURE_COPY_LOCATION textureLocation;
|
||||
textureLocation.pResource = texture->GetD3D12Resource();
|
||||
textureLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
textureLocation.SubresourceIndex = copy->destination.level;
|
||||
textureLocation.SubresourceIndex =
|
||||
texture->GetNumMipLevels() * copy->destination.slice +
|
||||
copy->destination.level;
|
||||
|
||||
for (uint32_t i = 0; i < copySplit.count; ++i) {
|
||||
auto& info = copySplit.copies[i];
|
||||
|
@ -379,7 +381,8 @@ namespace dawn_native { namespace d3d12 {
|
|||
D3D12_TEXTURE_COPY_LOCATION textureLocation;
|
||||
textureLocation.pResource = texture->GetD3D12Resource();
|
||||
textureLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
textureLocation.SubresourceIndex = copy->source.level;
|
||||
textureLocation.SubresourceIndex =
|
||||
texture->GetNumMipLevels() * copy->source.slice + copy->source.level;
|
||||
|
||||
for (uint32_t i = 0; i < copySplit.count; ++i) {
|
||||
auto& info = copySplit.copies[i];
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace dawn_native { namespace d3d12 {
|
|||
TextureCopySplit copy;
|
||||
|
||||
if (z != 0 || depth > 1) {
|
||||
// TODO(enga@google.com): Handle 3D / 2D arrays
|
||||
// TODO(enga@google.com): Handle 3D
|
||||
ASSERT(false);
|
||||
return copy;
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ namespace dawn_native { namespace d3d12 {
|
|||
resourceDescriptor.Alignment = 0;
|
||||
resourceDescriptor.Width = GetWidth();
|
||||
resourceDescriptor.Height = GetHeight();
|
||||
resourceDescriptor.DepthOrArraySize = static_cast<UINT16>(GetDepth());
|
||||
resourceDescriptor.DepthOrArraySize = GetDepthOrArraySize();
|
||||
resourceDescriptor.MipLevels = static_cast<UINT16>(GetNumMipLevels());
|
||||
resourceDescriptor.Format = D3D12TextureFormat(GetFormat());
|
||||
resourceDescriptor.SampleDesc.Count = 1;
|
||||
|
@ -151,6 +151,15 @@ namespace dawn_native { namespace d3d12 {
|
|||
return mResourcePtr;
|
||||
}
|
||||
|
||||
UINT16 Texture::GetDepthOrArraySize() {
|
||||
switch (GetDimension()) {
|
||||
case dawn::TextureDimension::e2D:
|
||||
return static_cast<UINT16>(GetArrayLayers());
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void Texture::TransitionUsageNow(ComPtr<ID3D12GraphicsCommandList> commandList,
|
||||
dawn::TextureUsageBit usage) {
|
||||
// Avoid transitioning the texture when it isn't needed.
|
||||
|
|
|
@ -38,6 +38,8 @@ namespace dawn_native { namespace d3d12 {
|
|||
dawn::TextureUsageBit usage);
|
||||
|
||||
private:
|
||||
UINT16 GetDepthOrArraySize();
|
||||
|
||||
ComPtr<ID3D12Resource> mResource = {};
|
||||
ID3D12Resource* mResourcePtr = nullptr;
|
||||
dawn::TextureUsageBit mLastUsage = dawn::TextureUsageBit::None;
|
||||
|
|
|
@ -270,7 +270,7 @@ namespace dawn_native { namespace metal {
|
|||
sourceBytesPerImage:(copy->rowPitch * dst.height)
|
||||
sourceSize:size
|
||||
toTexture:texture->GetMTLTexture()
|
||||
destinationSlice:0
|
||||
destinationSlice:dst.slice
|
||||
destinationLevel:dst.level
|
||||
destinationOrigin:origin];
|
||||
} break;
|
||||
|
@ -294,7 +294,7 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
encoders.EnsureBlit(commandBuffer);
|
||||
[encoders.blit copyFromTexture:texture->GetMTLTexture()
|
||||
sourceSlice:0
|
||||
sourceSlice:src.slice
|
||||
sourceLevel:src.level
|
||||
sourceOrigin:origin
|
||||
sourceSize:size
|
||||
|
|
|
@ -58,10 +58,11 @@ namespace dawn_native { namespace metal {
|
|||
return result;
|
||||
}
|
||||
|
||||
MTLTextureType MetalTextureType(dawn::TextureDimension dimension) {
|
||||
MTLTextureType MetalTextureType(dawn::TextureDimension dimension,
|
||||
unsigned int arrayLayers) {
|
||||
switch (dimension) {
|
||||
case dawn::TextureDimension::e2D:
|
||||
return MTLTextureType2D;
|
||||
return (arrayLayers > 1) ? MTLTextureType2DArray : MTLTextureType2D;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,14 +71,14 @@ namespace dawn_native { namespace metal {
|
|||
: TextureBase(device, descriptor) {
|
||||
auto desc = [MTLTextureDescriptor new];
|
||||
[desc autorelease];
|
||||
desc.textureType = MetalTextureType(GetDimension());
|
||||
desc.textureType = MetalTextureType(GetDimension(), GetArrayLayers());
|
||||
desc.usage = MetalTextureUsage(GetUsage());
|
||||
desc.pixelFormat = MetalPixelFormat(GetFormat());
|
||||
desc.width = GetWidth();
|
||||
desc.height = GetHeight();
|
||||
desc.depth = GetDepth();
|
||||
desc.mipmapLevelCount = GetNumMipLevels();
|
||||
desc.arrayLength = 1;
|
||||
desc.arrayLength = GetArrayLayers();
|
||||
desc.storageMode = MTLStorageModePrivate;
|
||||
|
||||
auto mtlDevice = device->GetMTLDevice();
|
||||
|
|
|
@ -331,13 +331,28 @@ namespace dawn_native { namespace opengl {
|
|||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(target, texture->GetHandle());
|
||||
|
||||
ASSERT(texture->GetDimension() == dawn::TextureDimension::e2D);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH,
|
||||
copy->rowPitch / TextureFormatPixelSize(texture->GetFormat()));
|
||||
glTexSubImage2D(target, dst.level, dst.x, dst.y, dst.width, dst.height,
|
||||
switch (texture->GetDimension()) {
|
||||
case dawn::TextureDimension::e2D:
|
||||
if (texture->GetArrayLayers() > 1) {
|
||||
glTexSubImage3D(
|
||||
target, dst.level, dst.x, dst.y, dst.slice, dst.width,
|
||||
dst.height, 1, format.format, format.type,
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(src.offset)));
|
||||
} else {
|
||||
glTexSubImage2D(
|
||||
target, dst.level, dst.x, dst.y, dst.width, dst.height,
|
||||
format.format, format.type,
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(src.offset)));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
} break;
|
||||
|
||||
|
@ -348,18 +363,31 @@ namespace dawn_native { namespace opengl {
|
|||
Texture* texture = ToBackend(src.texture.Get());
|
||||
Buffer* buffer = ToBackend(dst.buffer.Get());
|
||||
auto format = texture->GetGLFormat();
|
||||
GLenum target = texture->GetGLTarget();
|
||||
|
||||
// The only way to move data from a texture to a buffer in GL is via
|
||||
// glReadPixels with a pack buffer. Create a temporary FBO for the copy.
|
||||
ASSERT(texture->GetDimension() == dawn::TextureDimension::e2D);
|
||||
glBindTexture(GL_TEXTURE_2D, texture->GetHandle());
|
||||
glBindTexture(target, texture->GetHandle());
|
||||
|
||||
GLuint readFBO = 0;
|
||||
glGenFramebuffers(1, &readFBO);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, readFBO);
|
||||
switch (texture->GetDimension()) {
|
||||
case dawn::TextureDimension::e2D:
|
||||
if (texture->GetArrayLayers() > 1) {
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
texture->GetHandle(), src.level,
|
||||
src.slice);
|
||||
} else {
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, texture->GetHandle(),
|
||||
src.level);
|
||||
}
|
||||
break;
|
||||
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
texture->GetHandle(), src.level);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer->GetHandle());
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH,
|
||||
|
|
|
@ -24,10 +24,11 @@ namespace dawn_native { namespace opengl {
|
|||
|
||||
namespace {
|
||||
|
||||
GLenum TargetForDimension(dawn::TextureDimension dimension) {
|
||||
GLenum TargetForDimensionAndArrayLayers(dawn::TextureDimension dimension,
|
||||
uint32_t arrayLayer) {
|
||||
switch (dimension) {
|
||||
case dawn::TextureDimension::e2D:
|
||||
return GL_TEXTURE_2D;
|
||||
return (arrayLayer > 1) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -74,19 +75,32 @@ namespace dawn_native { namespace opengl {
|
|||
|
||||
Texture::Texture(Device* device, const TextureDescriptor* descriptor, GLuint handle)
|
||||
: TextureBase(device, descriptor), mHandle(handle) {
|
||||
mTarget = TargetForDimension(GetDimension());
|
||||
mTarget = TargetForDimensionAndArrayLayers(GetDimension(), GetArrayLayers());
|
||||
|
||||
uint32_t width = GetWidth();
|
||||
uint32_t height = GetHeight();
|
||||
uint32_t levels = GetNumMipLevels();
|
||||
uint32_t arrayLayers = GetArrayLayers();
|
||||
|
||||
auto formatInfo = GetGLFormatInfo(GetFormat());
|
||||
|
||||
glBindTexture(mTarget, handle);
|
||||
|
||||
for (uint32_t i = 0; i < levels; ++i) {
|
||||
glTexImage2D(mTarget, i, formatInfo.internalFormat, width, height, 0, formatInfo.format,
|
||||
formatInfo.type, nullptr);
|
||||
switch (GetDimension()) {
|
||||
case dawn::TextureDimension::e2D:
|
||||
if (arrayLayers > 1) {
|
||||
glTexImage3D(mTarget, i, formatInfo.internalFormat, width, height,
|
||||
arrayLayers, 0, formatInfo.format, formatInfo.type, nullptr);
|
||||
} else {
|
||||
glTexImage2D(mTarget, i, formatInfo.internalFormat, width, height, 0,
|
||||
formatInfo.format, formatInfo.type, nullptr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
width = std::max(uint32_t(1), width / 2);
|
||||
height = std::max(uint32_t(1), height / 2);
|
||||
}
|
||||
|
|
|
@ -365,11 +365,7 @@ TEST_P(CopyTests_T2B, RowPitchUnaligned) {
|
|||
}
|
||||
|
||||
// Test that copying regions of each texture 2D array layer works
|
||||
TEST_P(CopyTests_T2B, Texture2DArrayRegion)
|
||||
{
|
||||
// TODO(jiawei.shao@intel.com): support 2D array texture on OpenGL, D3D12 and Metal.
|
||||
DAWN_SKIP_TEST_IF(IsOpenGL() || IsD3D12() || IsMetal());
|
||||
|
||||
TEST_P(CopyTests_T2B, Texture2DArrayRegion) {
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
constexpr uint32_t kLayers = 6u;
|
||||
|
@ -378,9 +374,6 @@ TEST_P(CopyTests_T2B, Texture2DArrayRegion)
|
|||
|
||||
// Test that copying texture 2D array mips with 256-byte aligned sizes works
|
||||
TEST_P(CopyTests_T2B, Texture2DArrayMip) {
|
||||
// TODO(jiawei.shao@intel.com): support 2D array texture on OpenGL, D3D12 and Metal.
|
||||
DAWN_SKIP_TEST_IF(IsOpenGL() || IsD3D12() || IsMetal());
|
||||
|
||||
constexpr uint32_t kWidth = 256;
|
||||
constexpr uint32_t kHeight = 128;
|
||||
constexpr uint32_t kLayers = 6u;
|
||||
|
|
Loading…
Reference in New Issue