OpenGL: refactor all texture uploads.
We augment the DoTexSubImage() call for the desktop GL fast path
for compressed textures (upload in a single call where possible).
Bug: dawn:684
Change-Id: Id67c39b1efbc8b435b58064cad66a55c153ce675
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/47240
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index aed04f1..8f5c101 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -604,11 +604,7 @@
CopyBufferToTextureCmd* copy = mCommands.NextCommand<CopyBufferToTextureCmd>();
auto& src = copy->source;
auto& dst = copy->destination;
- auto& copySize = copy->copySize;
Buffer* buffer = ToBackend(src.buffer.Get());
- Texture* texture = ToBackend(dst.texture.Get());
- GLenum target = texture->GetGLTarget();
- const GLFormat& format = texture->GetGLFormat();
if (dst.aspect == Aspect::Stencil) {
return DAWN_VALIDATION_ERROR(
@@ -618,108 +614,15 @@
buffer->EnsureDataInitialized();
- ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
- SubresourceRange subresources =
- GetSubresourcesAffectedByCopy(dst, copy->copySize);
- if (IsCompleteSubresourceCopiedTo(texture, copySize, dst.mipLevel)) {
- texture->SetIsSubresourceContentInitialized(true, subresources);
- } else {
- texture->EnsureSubresourceContentInitialized(subresources);
- }
-
gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->GetHandle());
TextureDataLayout dataLayout;
dataLayout.offset = 0;
dataLayout.bytesPerRow = src.bytesPerRow;
dataLayout.rowsPerImage = src.rowsPerImage;
- gl.ActiveTexture(GL_TEXTURE0);
- gl.BindTexture(target, texture->GetHandle());
- const Format& formatInfo = texture->GetFormat();
- const TexelBlockInfo& blockInfo = formatInfo.GetAspectInfo(dst.aspect).block;
-
- if (formatInfo.isCompressed) {
- ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
-
- Extent3D copyExtent = ComputeTextureCopyExtent(dst, copySize);
-
- // In GLES glPixelStorei() doesn't affect CompressedTexSubImage*D() and
- // GL_UNPACK_COMPRESSED_BLOCK_* isn't defined, so we have to workaround
- // this limitation by copying the compressed texture data once per row.
- // See OpenGL ES 3.2 SPEC Chapter 8.4.1, "Pixel Storage Modes and Pixel
- // Buffer Objects" for more details.
- if (gl.GetVersion().IsES()) {
- DoTexSubImage(gl, dst, reinterpret_cast<void*>(src.offset), dataLayout,
- copySize);
- } else {
- gl.PixelStorei(GL_UNPACK_ROW_LENGTH,
- src.bytesPerRow / blockInfo.byteSize * blockInfo.width);
- gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT,
- src.rowsPerImage * blockInfo.height);
- gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, blockInfo.byteSize);
- gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, blockInfo.width);
- gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, blockInfo.height);
- gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_DEPTH, 1);
-
- uint64_t copyDataSize = (copySize.width / blockInfo.width) *
- (copySize.height / blockInfo.height) *
- blockInfo.byteSize *
- copySize.depthOrArrayLayers;
-
- if (texture->GetArrayLayers() > 1) {
- gl.CompressedTexSubImage3D(
- target, dst.mipLevel, dst.origin.x, dst.origin.y, dst.origin.z,
- copyExtent.width, copyExtent.height,
- copyExtent.depthOrArrayLayers, format.internalFormat,
- copyDataSize,
- reinterpret_cast<void*>(static_cast<uintptr_t>(src.offset)));
- } else {
- gl.CompressedTexSubImage2D(
- target, dst.mipLevel, dst.origin.x, dst.origin.y,
- copyExtent.width, copyExtent.height, format.internalFormat,
- copyDataSize,
- reinterpret_cast<void*>(static_cast<uintptr_t>(src.offset)));
- }
-
- gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
- gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
- gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, 0);
- gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, 0);
- gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, 0);
- gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_DEPTH, 0);
- }
- } else {
- gl.PixelStorei(GL_UNPACK_ROW_LENGTH,
- src.bytesPerRow / blockInfo.byteSize * blockInfo.width);
- gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, src.rowsPerImage * blockInfo.height);
- switch (texture->GetDimension()) {
- case wgpu::TextureDimension::e2D:
- if (texture->GetArrayLayers() > 1) {
- gl.TexSubImage3D(target, dst.mipLevel, dst.origin.x,
- dst.origin.y, dst.origin.z, copySize.width,
- copySize.height, copySize.depthOrArrayLayers,
- format.format, format.type,
- reinterpret_cast<void*>(
- static_cast<uintptr_t>(src.offset)));
- } else {
- gl.TexSubImage2D(target, dst.mipLevel, dst.origin.x,
- dst.origin.y, copySize.width, copySize.height,
- format.format, format.type,
- reinterpret_cast<void*>(
- static_cast<uintptr_t>(src.offset)));
- }
- break;
-
- case wgpu::TextureDimension::e1D:
- case wgpu::TextureDimension::e3D:
- UNREACHABLE();
- }
-
- gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
- gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
- }
-
+ DoTexSubImage(gl, dst, reinterpret_cast<void*>(src.offset), dataLayout,
+ copy->copySize);
gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
break;
}
@@ -1362,12 +1265,11 @@
const TextureCopy& destination,
const void* data,
const TextureDataLayout& dataLayout,
- const Extent3D& writeSizePixel) {
+ const Extent3D& copySize) {
Texture* texture = ToBackend(destination.texture.Get());
- SubresourceRange range(Aspect::Color,
- {destination.origin.z, writeSizePixel.depthOrArrayLayers},
- {destination.mipLevel, 1});
- if (IsCompleteSubresourceCopiedTo(texture, writeSizePixel, destination.mipLevel)) {
+ ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
+ SubresourceRange range = GetSubresourcesAffectedByCopy(destination, copySize);
+ if (IsCompleteSubresourceCopiedTo(texture, copySize, destination.mipLevel)) {
texture->SetIsSubresourceContentInitialized(true, range);
} else {
texture->EnsureSubresourceContentInitialized(range);
@@ -1376,80 +1278,119 @@
const GLFormat& format = texture->GetGLFormat();
GLenum target = texture->GetGLTarget();
data = static_cast<const uint8_t*>(data) + dataLayout.offset;
+ gl.ActiveTexture(GL_TEXTURE0);
gl.BindTexture(target, texture->GetHandle());
const TexelBlockInfo& blockInfo =
texture->GetFormat().GetAspectInfo(destination.aspect).block;
if (texture->GetFormat().isCompressed) {
- size_t imageSize = writeSizePixel.width / blockInfo.width * blockInfo.byteSize;
+ size_t rowSize = copySize.width / blockInfo.width * blockInfo.byteSize;
Extent3D virtSize = texture->GetMipLevelVirtualSize(destination.mipLevel);
- uint32_t width = std::min(writeSizePixel.width, virtSize.width - destination.origin.x);
- uint32_t x = destination.origin.x;
+ uint32_t width = std::min(copySize.width, virtSize.width - destination.origin.x);
- // For now, we use row-by-row texture uploads of compressed textures in all cases.
- // TODO(crbug.com/dawn/684): For contiguous cases, we should be able to use a single
- // texture upload per layer, as we do in the non-compressed case.
- if (texture->GetArrayLayers() == 1) {
- const uint8_t* d = static_cast<const uint8_t*>(data);
-
- for (uint32_t y = destination.origin.y;
- y < destination.origin.y + writeSizePixel.height; y += blockInfo.height) {
- uint32_t height = std::min(blockInfo.height, virtSize.height - y);
- gl.CompressedTexSubImage2D(target, destination.mipLevel, x, y, width, height,
- format.internalFormat, imageSize, d);
- d += dataLayout.bytesPerRow;
- }
- } else {
- const uint8_t* slice = static_cast<const uint8_t*>(data);
-
- for (uint32_t z = destination.origin.z;
- z < destination.origin.z + writeSizePixel.depthOrArrayLayers; ++z) {
- const uint8_t* d = slice;
+ // In GLES glPixelStorei() doesn't affect CompressedTexSubImage*D() and
+ // GL_UNPACK_COMPRESSED_BLOCK_* isn't defined, so we have to workaround
+ // this limitation by copying the compressed texture data once per row.
+ // See OpenGL ES 3.2 SPEC Chapter 8.4.1, "Pixel Storage Modes and Pixel
+ // Buffer Objects" for more details. For Desktop GL, we use row-by-row
+ // copies only for uploads where bytesPerRow is not a multiple of byteSize.
+ if (gl.GetVersion().IsES() || dataLayout.bytesPerRow % blockInfo.byteSize != 0) {
+ uint32_t x = destination.origin.x;
+ if (texture->GetArrayLayers() == 1) {
+ const uint8_t* d = static_cast<const uint8_t*>(data);
for (uint32_t y = destination.origin.y;
- y < destination.origin.y + writeSizePixel.height; y += blockInfo.height) {
+ y < destination.origin.y + copySize.height; y += blockInfo.height) {
uint32_t height = std::min(blockInfo.height, virtSize.height - y);
- gl.CompressedTexSubImage3D(target, destination.mipLevel, x, y, z, width,
- height, 1, format.internalFormat, imageSize, d);
+ gl.CompressedTexSubImage2D(target, destination.mipLevel, x, y, width,
+ height, format.internalFormat, rowSize, d);
d += dataLayout.bytesPerRow;
}
+ } else {
+ const uint8_t* slice = static_cast<const uint8_t*>(data);
- slice += dataLayout.rowsPerImage * dataLayout.bytesPerRow;
+ for (uint32_t z = destination.origin.z;
+ z < destination.origin.z + copySize.depthOrArrayLayers; ++z) {
+ const uint8_t* d = slice;
+
+ for (uint32_t y = destination.origin.y;
+ y < destination.origin.y + copySize.height; y += blockInfo.height) {
+ uint32_t height = std::min(blockInfo.height, virtSize.height - y);
+ gl.CompressedTexSubImage3D(target, destination.mipLevel, x, y, z, width,
+ height, 1, format.internalFormat, rowSize,
+ d);
+ d += dataLayout.bytesPerRow;
+ }
+
+ slice += dataLayout.rowsPerImage * dataLayout.bytesPerRow;
+ }
}
+ } else {
+ size_t imageSize =
+ rowSize * (copySize.height / blockInfo.height) * copySize.depthOrArrayLayers;
+
+ uint32_t height = std::min(copySize.height, virtSize.height - destination.origin.y);
+
+ gl.PixelStorei(GL_UNPACK_ROW_LENGTH,
+ dataLayout.bytesPerRow / blockInfo.byteSize * blockInfo.width);
+ gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, blockInfo.byteSize);
+ gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, blockInfo.width);
+ gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, blockInfo.height);
+ gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_DEPTH, 1);
+
+ if (texture->GetArrayLayers() > 1) {
+ gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT,
+ dataLayout.rowsPerImage * blockInfo.height);
+ gl.CompressedTexSubImage3D(target, destination.mipLevel, destination.origin.x,
+ destination.origin.y, destination.origin.z, width,
+ height, copySize.depthOrArrayLayers,
+ format.internalFormat, imageSize, data);
+ gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
+ } else {
+ gl.CompressedTexSubImage2D(target, destination.mipLevel, destination.origin.x,
+ destination.origin.y, width, height,
+ format.internalFormat, imageSize, data);
+ }
+
+ gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, 0);
+ gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, 0);
+ gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, 0);
+ gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_DEPTH, 0);
}
} else if (dataLayout.bytesPerRow % blockInfo.byteSize == 0) {
gl.PixelStorei(GL_UNPACK_ROW_LENGTH,
dataLayout.bytesPerRow / blockInfo.byteSize * blockInfo.width);
if (texture->GetArrayLayers() == 1) {
gl.TexSubImage2D(target, destination.mipLevel, destination.origin.x,
- destination.origin.y, writeSizePixel.width, writeSizePixel.height,
+ destination.origin.y, copySize.width, copySize.height,
format.format, format.type, data);
} else {
gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, dataLayout.rowsPerImage * blockInfo.height);
gl.TexSubImage3D(target, destination.mipLevel, destination.origin.x,
- destination.origin.y, destination.origin.z, writeSizePixel.width,
- writeSizePixel.height, writeSizePixel.depthOrArrayLayers,
- format.format, format.type, data);
+ destination.origin.y, destination.origin.z, copySize.width,
+ copySize.height, copySize.depthOrArrayLayers, format.format,
+ format.type, data);
gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
}
gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
} else {
if (texture->GetArrayLayers() == 1) {
const uint8_t* d = static_cast<const uint8_t*>(data);
- for (uint32_t y = 0; y < writeSizePixel.height; ++y) {
+ for (uint32_t y = 0; y < copySize.height; ++y) {
gl.TexSubImage2D(target, destination.mipLevel, destination.origin.x,
- destination.origin.y + y, writeSizePixel.width, 1,
- format.format, format.type, d);
+ destination.origin.y + y, copySize.width, 1, format.format,
+ format.type, d);
d += dataLayout.bytesPerRow;
}
} else {
const uint8_t* slice = static_cast<const uint8_t*>(data);
- for (uint32_t z = 0; z < writeSizePixel.depthOrArrayLayers; ++z) {
+ for (uint32_t z = 0; z < copySize.depthOrArrayLayers; ++z) {
const uint8_t* d = slice;
- for (uint32_t y = 0; y < writeSizePixel.height; ++y) {
+ for (uint32_t y = 0; y < copySize.height; ++y) {
gl.TexSubImage3D(target, destination.mipLevel, destination.origin.x,
destination.origin.y + y, destination.origin.z + z,
- writeSizePixel.width, 1, 1, format.format, format.type, d);
+ copySize.width, 1, 1, format.format, format.type, d);
d += dataLayout.bytesPerRow;
}
slice += dataLayout.rowsPerImage * dataLayout.bytesPerRow;
diff --git a/src/dawn_native/opengl/CommandBufferGL.h b/src/dawn_native/opengl/CommandBufferGL.h
index ae53e6a..fde8751 100644
--- a/src/dawn_native/opengl/CommandBufferGL.h
+++ b/src/dawn_native/opengl/CommandBufferGL.h
@@ -43,7 +43,7 @@
const TextureCopy& destination,
const void* data,
const TextureDataLayout& dataLayout,
- const Extent3D& writeSizePixel);
+ const Extent3D& copySize);
}} // namespace dawn_native::opengl
#endif // DAWNNATIVE_OPENGL_COMMANDBUFFERGL_H_