OpenGL: Refactor texture uploads.
Move texture uploads into CommandBufferGL::DoTexSubImage() and use it
for both CommandBuffer CopyBufferToTexture and
QueueGL::WriteTextureImpl(). On the CB side, For now this is only used
for compressed ES textures. Desktop GL has a fast-path for compressed
textures that isn't currently implemented.
Bug: dawn:684
Change-Id: I4da02e9c96c13fd71d133778168a5597efa7b59a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/47123
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Stephen White <senorblanco@chromium.org>
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index 6573d12..aed04f1 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -628,6 +628,11 @@
}
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());
@@ -645,52 +650,8 @@
// See OpenGL ES 3.2 SPEC Chapter 8.4.1, "Pixel Storage Modes and Pixel
// Buffer Objects" for more details.
if (gl.GetVersion().IsES()) {
- uint64_t copyDataSizePerBlockRow =
- (copySize.width / blockInfo.width) * blockInfo.byteSize;
- size_t copyBlockRowsPerImage = copySize.height / blockInfo.height;
-
- if (texture->GetArrayLayers() > 1) {
- // TODO(jiawei.shao@intel.com): do a single copy when the data is
- // correctly packed.
- for (size_t copyZ = 0; copyZ < copyExtent.depthOrArrayLayers;
- ++copyZ) {
- uintptr_t offsetPerImage = static_cast<uintptr_t>(
- src.offset + copyZ * src.bytesPerRow * src.rowsPerImage);
- uint32_t dstOriginY = dst.origin.y;
- uint32_t dstOriginZ = dst.origin.z + copyZ;
-
- for (size_t copyBlockRow = 0;
- copyBlockRow < copyBlockRowsPerImage; ++copyBlockRow) {
- gl.CompressedTexSubImage3D(
- target, dst.mipLevel, dst.origin.x, dstOriginY,
- dstOriginZ, copyExtent.width, blockInfo.height, 1,
- format.internalFormat, copyDataSizePerBlockRow,
- reinterpret_cast<void*>(
- static_cast<uintptr_t>(offsetPerImage)));
-
- offsetPerImage += src.bytesPerRow;
- dstOriginY += blockInfo.height;
- }
- }
- } else {
- uintptr_t offset = static_cast<uintptr_t>(src.offset);
- uint32_t dstOriginY = dst.origin.y;
-
- // TODO(jiawei.shao@intel.com): do a single copy when the data is
- // correctly packed.
- for (size_t copyBlockRow = 0; copyBlockRow < copyBlockRowsPerImage;
- ++copyBlockRow) {
- gl.CompressedTexSubImage2D(
- target, dst.mipLevel, dst.origin.x, dstOriginY,
- copyExtent.width, blockInfo.height, format.internalFormat,
- copyDataSizePerBlockRow,
- reinterpret_cast<void*>(static_cast<uintptr_t>(offset)));
-
- offset += src.bytesPerRow;
- dstOriginY += blockInfo.height;
- }
- }
-
+ DoTexSubImage(gl, dst, reinterpret_cast<void*>(src.offset), dataLayout,
+ copySize);
} else {
gl.PixelStorei(GL_UNPACK_ROW_LENGTH,
src.bytesPerRow / blockInfo.byteSize * blockInfo.width);
@@ -1397,4 +1358,104 @@
UNREACHABLE();
}
+ void DoTexSubImage(const OpenGLFunctions& gl,
+ const TextureCopy& destination,
+ const void* data,
+ const TextureDataLayout& dataLayout,
+ const Extent3D& writeSizePixel) {
+ Texture* texture = ToBackend(destination.texture.Get());
+ SubresourceRange range(Aspect::Color,
+ {destination.origin.z, writeSizePixel.depthOrArrayLayers},
+ {destination.mipLevel, 1});
+ if (IsCompleteSubresourceCopiedTo(texture, writeSizePixel, destination.mipLevel)) {
+ texture->SetIsSubresourceContentInitialized(true, range);
+ } else {
+ texture->EnsureSubresourceContentInitialized(range);
+ }
+
+ const GLFormat& format = texture->GetGLFormat();
+ GLenum target = texture->GetGLTarget();
+ data = static_cast<const uint8_t*>(data) + dataLayout.offset;
+ 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;
+ Extent3D virtSize = texture->GetMipLevelVirtualSize(destination.mipLevel);
+ uint32_t width = std::min(writeSizePixel.width, virtSize.width - destination.origin.x);
+ uint32_t x = 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;
+
+ 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.CompressedTexSubImage3D(target, destination.mipLevel, x, y, z, width,
+ height, 1, format.internalFormat, imageSize, d);
+ d += dataLayout.bytesPerRow;
+ }
+
+ slice += dataLayout.rowsPerImage * dataLayout.bytesPerRow;
+ }
+ }
+ } 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,
+ 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);
+ 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) {
+ gl.TexSubImage2D(target, destination.mipLevel, destination.origin.x,
+ destination.origin.y + y, writeSizePixel.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) {
+ const uint8_t* d = slice;
+ for (uint32_t y = 0; y < writeSizePixel.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);
+ d += dataLayout.bytesPerRow;
+ }
+ slice += dataLayout.rowsPerImage * dataLayout.bytesPerRow;
+ }
+ }
+ }
+ }
+
}} // namespace dawn_native::opengl
diff --git a/src/dawn_native/opengl/CommandBufferGL.h b/src/dawn_native/opengl/CommandBufferGL.h
index c21f574..ae53e6a 100644
--- a/src/dawn_native/opengl/CommandBufferGL.h
+++ b/src/dawn_native/opengl/CommandBufferGL.h
@@ -24,6 +24,7 @@
namespace dawn_native { namespace opengl {
class Device;
+ struct OpenGLFunctions;
class CommandBuffer final : public CommandBufferBase {
public:
@@ -36,6 +37,13 @@
MaybeError ExecuteRenderPass(BeginRenderPassCmd* renderPass);
};
+ // Like glTexSubImage*, the "data" argument is either a pointer to image data or
+ // an offset if a PBO is bound.
+ void DoTexSubImage(const OpenGLFunctions& gl,
+ const TextureCopy& destination,
+ const void* data,
+ const TextureDataLayout& dataLayout,
+ const Extent3D& writeSizePixel);
}} // namespace dawn_native::opengl
#endif // DAWNNATIVE_OPENGL_COMMANDBUFFERGL_H_
diff --git a/src/dawn_native/opengl/QueueGL.cpp b/src/dawn_native/opengl/QueueGL.cpp
index 17260b9..167f8c4 100644
--- a/src/dawn_native/opengl/QueueGL.cpp
+++ b/src/dawn_native/opengl/QueueGL.cpp
@@ -56,101 +56,13 @@
const void* data,
const TextureDataLayout& dataLayout,
const Extent3D& writeSizePixel) {
- const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
-
- Texture* texture = ToBackend(destination.texture);
- SubresourceRange range(Aspect::Color,
- {destination.origin.z, writeSizePixel.depthOrArrayLayers},
- {destination.mipLevel, 1});
- if (IsCompleteSubresourceCopiedTo(texture, writeSizePixel, destination.mipLevel)) {
- texture->SetIsSubresourceContentInitialized(true, range);
- } else {
- texture->EnsureSubresourceContentInitialized(range);
- }
-
- const GLFormat& format = texture->GetGLFormat();
- GLenum target = texture->GetGLTarget();
- data = static_cast<const uint8_t*>(data) + dataLayout.offset;
- 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;
- Extent3D virtSize = texture->GetMipLevelVirtualSize(destination.mipLevel);
- uint32_t width = std::min(writeSizePixel.width, virtSize.width - destination.origin.x);
- uint32_t x = 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;
-
- 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.CompressedTexSubImage3D(target, destination.mipLevel, x, y, z, width,
- height, 1, format.internalFormat, imageSize, d);
- d += dataLayout.bytesPerRow;
- }
-
- slice += dataLayout.rowsPerImage * dataLayout.bytesPerRow;
- }
- }
- } 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,
- 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);
- 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) {
- gl.TexSubImage2D(target, destination.mipLevel, destination.origin.x,
- destination.origin.y + y, writeSizePixel.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) {
- const uint8_t* d = slice;
- for (uint32_t y = 0; y < writeSizePixel.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);
- d += dataLayout.bytesPerRow;
- }
- slice += dataLayout.rowsPerImage * dataLayout.bytesPerRow;
- }
- }
- }
+ TextureCopy textureCopy;
+ textureCopy.texture = destination.texture;
+ textureCopy.mipLevel = destination.mipLevel;
+ textureCopy.origin = destination.origin;
+ textureCopy.aspect =
+ SelectFormatAspects(destination.texture->GetFormat(), destination.aspect);
+ DoTexSubImage(ToBackend(GetDevice())->gl, textureCopy, data, dataLayout, writeSizePixel);
return {};
}