aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeoff Lang <geofflang@chromium.org>2024-04-05 10:29:23 -0400
committerAngle LUCI CQ <angle-scoped@luci-project-accounts.iam.gserviceaccount.com>2024-04-12 15:13:15 +0000
commitf4485224fe4b000cb1a0106000ebd8adcc4e2d8b (patch)
treefa938c31a7cccb4a6598d9f7a98e2234ec20686c
parente088af30ff462bae7db2179427ccedbe4bc82001 (diff)
downloadangle-f4485224fe4b000cb1a0106000ebd8adcc4e2d8b.tar.gz
WebGPU: Implement glBufferData and glBufferSubData
Define several usages for WebGPU buffers that map to wgpu buffer usage flags. Maintain a set of buffers by usage and a serial of the one with the most recent data. Defer creation of the buffer as long as possible to take advantage of the WebGPU mapAtCreation flag for data upload. If we ever have to unmap these buffers, staging buffers must be used to upload afterwards. Add some helpers for getting Device and Instance from a gl::Context. Bug: angleproject:8654 Change-Id: Ibb8147119af8a98738fc4d579830a02ccaa1d7c5 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5426813 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Liza Burakova <liza@chromium.org>
-rw-r--r--src/libANGLE/renderer/wgpu/BufferWgpu.cpp112
-rw-r--r--src/libANGLE/renderer/wgpu/BufferWgpu.h15
-rw-r--r--src/libANGLE/renderer/wgpu/DisplayWgpu.cpp5
-rw-r--r--src/libANGLE/renderer/wgpu/DisplayWgpu.h1
-rw-r--r--src/libANGLE/renderer/wgpu/FramebufferWgpu.cpp4
-rw-r--r--src/libANGLE/renderer/wgpu/TextureWgpu.cpp6
-rw-r--r--src/libANGLE/renderer/wgpu/wgpu_helpers.cpp119
-rw-r--r--src/libANGLE/renderer/wgpu/wgpu_helpers.h57
-rw-r--r--src/libANGLE/renderer/wgpu/wgpu_utils.cpp44
-rw-r--r--src/libANGLE/renderer/wgpu/wgpu_utils.h28
-rw-r--r--src/tests/gl_tests/RendererTest.cpp29
11 files changed, 382 insertions, 38 deletions
diff --git a/src/libANGLE/renderer/wgpu/BufferWgpu.cpp b/src/libANGLE/renderer/wgpu/BufferWgpu.cpp
index fc2f21fe89..2087e287e5 100644
--- a/src/libANGLE/renderer/wgpu/BufferWgpu.cpp
+++ b/src/libANGLE/renderer/wgpu/BufferWgpu.cpp
@@ -14,31 +14,89 @@
#include "libANGLE/Context.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/renderer/wgpu/ContextWgpu.h"
+#include "libANGLE/renderer/wgpu/wgpu_utils.h"
namespace rx
{
+namespace
+{
+// Based on a buffer binding target, compute the default wgpu usage flags. More can be added if the
+// buffer is used in new ways.
+wgpu::BufferUsage GetDefaultWGPUBufferUsageForBinding(gl::BufferBinding binding)
+{
+ switch (binding)
+ {
+ case gl::BufferBinding::Array:
+ case gl::BufferBinding::ElementArray:
+ return wgpu::BufferUsage::Vertex | wgpu::BufferUsage::Index |
+ wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
+
+ case gl::BufferBinding::Uniform:
+ return wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopySrc |
+ wgpu::BufferUsage::CopyDst;
+
+ case gl::BufferBinding::PixelPack:
+ return wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
+
+ case gl::BufferBinding::PixelUnpack:
+ return wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc;
+
+ case gl::BufferBinding::CopyRead:
+ case gl::BufferBinding::CopyWrite:
+ case gl::BufferBinding::ShaderStorage:
+ case gl::BufferBinding::Texture:
+ case gl::BufferBinding::TransformFeedback:
+ case gl::BufferBinding::DispatchIndirect:
+ case gl::BufferBinding::DrawIndirect:
+ case gl::BufferBinding::AtomicCounter:
+ UNIMPLEMENTED();
+ return wgpu::BufferUsage::None;
+
+ default:
+ UNREACHABLE();
+ return wgpu::BufferUsage::None;
+ }
+}
+
+} // namespace
BufferWgpu::BufferWgpu(const gl::BufferState &state) : BufferImpl(state) {}
BufferWgpu::~BufferWgpu() {}
-angle::Result BufferWgpu::setDataWithUsageFlags(const gl::Context *context,
- gl::BufferBinding target,
- GLeglClientBufferEXT clientBuffer,
- const void *data,
- size_t size,
- gl::BufferUsage usage,
- GLbitfield flags)
-{
- return angle::Result::Continue;
-}
-
angle::Result BufferWgpu::setData(const gl::Context *context,
gl::BufferBinding target,
const void *data,
size_t size,
gl::BufferUsage usage)
{
+ ContextWgpu *contextWgpu = webgpu::GetImpl(context);
+ wgpu::Device device = webgpu::GetDevice(context);
+
+ bool hasData = data && size > 0;
+
+ // Allocate a new buffer if the current one is invalid, the size is different, or the current
+ // buffer cannot be mapped for writing when data needs to be uploaded.
+ if (!mBuffer.valid() || mBuffer.size() != size || (hasData && !mBuffer.canMapForWrite()))
+ {
+ // Allocate a new buffer
+ ANGLE_TRY(mBuffer.initBuffer(device, size, GetDefaultWGPUBufferUsageForBinding(target),
+ webgpu::MapAtCreation::Yes));
+ }
+
+ if (hasData)
+ {
+ ASSERT(mBuffer.canMapForWrite());
+
+ if (!mBuffer.getMappedState().has_value())
+ {
+ ANGLE_TRY(mBuffer.mapImmediate(contextWgpu, wgpu::MapMode::Write, 0, size));
+ }
+
+ uint8_t *mappedData = mBuffer.getMapWritePointer(0, size);
+ memcpy(mappedData, data, size);
+ }
+
return angle::Result::Continue;
}
@@ -48,6 +106,28 @@ angle::Result BufferWgpu::setSubData(const gl::Context *context,
size_t size,
size_t offset)
{
+ ContextWgpu *contextWgpu = webgpu::GetImpl(context);
+ wgpu::Device device = webgpu::GetDevice(context);
+
+ ASSERT(mBuffer.valid());
+ if (mBuffer.canMapForWrite())
+ {
+ if (!mBuffer.getMappedState().has_value())
+ {
+ ANGLE_TRY(mBuffer.mapImmediate(contextWgpu, wgpu::MapMode::Write, offset, size));
+ }
+
+ uint8_t *mappedData = mBuffer.getMapWritePointer(offset, size);
+ memcpy(mappedData, data, size);
+ }
+ else
+ {
+ // TODO: Upload into a staging buffer and copy to the destination buffer so that the copy
+ // happens at the right point in time for command buffer recording.
+ wgpu::Queue &queue = contextWgpu->getQueue();
+ queue.WriteBuffer(mBuffer.getBuffer(), offset, data, size);
+ }
+
return angle::Result::Continue;
}
@@ -90,14 +170,4 @@ angle::Result BufferWgpu::getIndexRange(const gl::Context *context,
return angle::Result::Continue;
}
-uint8_t *BufferWgpu::getDataPtr()
-{
- return nullptr;
-}
-
-const uint8_t *BufferWgpu::getDataPtr() const
-{
- return nullptr;
-}
-
} // namespace rx
diff --git a/src/libANGLE/renderer/wgpu/BufferWgpu.h b/src/libANGLE/renderer/wgpu/BufferWgpu.h
index 01ad4763b1..4d222c6cef 100644
--- a/src/libANGLE/renderer/wgpu/BufferWgpu.h
+++ b/src/libANGLE/renderer/wgpu/BufferWgpu.h
@@ -12,6 +12,10 @@
#include "libANGLE/renderer/BufferImpl.h"
+#include "libANGLE/renderer/wgpu/wgpu_helpers.h"
+
+#include <dawn/webgpu_cpp.h>
+
namespace rx
{
@@ -21,13 +25,6 @@ class BufferWgpu : public BufferImpl
BufferWgpu(const gl::BufferState &state);
~BufferWgpu() override;
- angle::Result setDataWithUsageFlags(const gl::Context *context,
- gl::BufferBinding target,
- GLeglClientBufferEXT clientBuffer,
- const void *data,
- size_t size,
- gl::BufferUsage usage,
- GLbitfield flags) override;
angle::Result setData(const gl::Context *context,
gl::BufferBinding target,
const void *data,
@@ -58,8 +55,8 @@ class BufferWgpu : public BufferImpl
bool primitiveRestartEnabled,
gl::IndexRange *outRange) override;
- uint8_t *getDataPtr();
- const uint8_t *getDataPtr() const;
+ private:
+ webgpu::BufferHelper mBuffer;
};
} // namespace rx
diff --git a/src/libANGLE/renderer/wgpu/DisplayWgpu.cpp b/src/libANGLE/renderer/wgpu/DisplayWgpu.cpp
index 30ed6cbbdc..4397a6ba17 100644
--- a/src/libANGLE/renderer/wgpu/DisplayWgpu.cpp
+++ b/src/libANGLE/renderer/wgpu/DisplayWgpu.cpp
@@ -215,6 +215,11 @@ ShareGroupImpl *DisplayWgpu::createShareGroup(const egl::ShareGroupState &state)
return new ShareGroupWgpu(state);
}
+wgpu::Instance DisplayWgpu::getInstance() const
+{
+ return mInstance->Get();
+}
+
void DisplayWgpu::generateExtensions(egl::DisplayExtensions *outExtensions) const
{
outExtensions->createContextRobustness = true;
diff --git a/src/libANGLE/renderer/wgpu/DisplayWgpu.h b/src/libANGLE/renderer/wgpu/DisplayWgpu.h
index 2217877477..9651c8dd52 100644
--- a/src/libANGLE/renderer/wgpu/DisplayWgpu.h
+++ b/src/libANGLE/renderer/wgpu/DisplayWgpu.h
@@ -92,6 +92,7 @@ class DisplayWgpu : public DisplayImpl
wgpu::Device &getDevice() { return mDevice; }
wgpu::Queue &getQueue() { return mQueue; }
+ wgpu::Instance getInstance() const;
private:
void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
diff --git a/src/libANGLE/renderer/wgpu/FramebufferWgpu.cpp b/src/libANGLE/renderer/wgpu/FramebufferWgpu.cpp
index 64ad148796..24709ebfd3 100644
--- a/src/libANGLE/renderer/wgpu/FramebufferWgpu.cpp
+++ b/src/libANGLE/renderer/wgpu/FramebufferWgpu.cpp
@@ -129,9 +129,7 @@ angle::Result FramebufferWgpu::readPixels(const gl::Context *context,
GLubyte *pixels = nullptr;
if (packBuffer != nullptr)
{
- BufferWgpu *packBufferGL = GetImplAs<BufferWgpu>(packBuffer);
- pixels = reinterpret_cast<GLubyte *>(packBufferGL->getDataPtr());
- pixels += reinterpret_cast<intptr_t>(ptrOrOffset);
+ UNREACHABLE();
}
else
{
diff --git a/src/libANGLE/renderer/wgpu/TextureWgpu.cpp b/src/libANGLE/renderer/wgpu/TextureWgpu.cpp
index bf6304952b..ae14794212 100644
--- a/src/libANGLE/renderer/wgpu/TextureWgpu.cpp
+++ b/src/libANGLE/renderer/wgpu/TextureWgpu.cpp
@@ -266,14 +266,14 @@ angle::Result TextureWgpu::redefineLevel(const gl::Context *context,
{
return angle::Result::Continue;
}
- ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context);
- DisplayWgpu *displayWgpu = contextWgpu->getDisplay();
+
+ wgpu::Device device = webgpu::GetDevice(context);
if (mImage == nullptr && !levelWithinRange)
{
mImage = new webgpu::ImageHelper();
webgpu::TextureInfo textureInfo = mImage->getWgpuTextureInfo(index);
- return mImage->initImage(displayWgpu->getDevice(), textureInfo.usage, textureInfo.dimension,
+ return mImage->initImage(device, textureInfo.usage, textureInfo.dimension,
gl_wgpu::getExtent3D(size), wgpu::TextureFormat::RGBA8Sint,
textureInfo.mipLevelCount, 1, 0);
}
diff --git a/src/libANGLE/renderer/wgpu/wgpu_helpers.cpp b/src/libANGLE/renderer/wgpu/wgpu_helpers.cpp
index c7810537ed..b621e4db38 100644
--- a/src/libANGLE/renderer/wgpu/wgpu_helpers.cpp
+++ b/src/libANGLE/renderer/wgpu/wgpu_helpers.cpp
@@ -6,6 +6,11 @@
#include "libANGLE/renderer/wgpu/wgpu_helpers.h"
+#include "libANGLE/renderer/wgpu/ContextWgpu.h"
+#include "libANGLE/renderer/wgpu/DisplayWgpu.h"
+
+namespace rx
+{
namespace webgpu
{
ImageHelper::ImageHelper() {}
@@ -69,4 +74,118 @@ TextureInfo ImageHelper::getWgpuTextureInfo(const gl::ImageIndex &index)
textureInfo.mipLevelCount = index.getLayerCount();
return textureInfo;
}
+
+BufferHelper::BufferHelper() {}
+
+BufferHelper::~BufferHelper() {}
+
+void BufferHelper::reset()
+{
+ mBuffer = nullptr;
+ mMappedState.reset();
+}
+
+angle::Result BufferHelper::initBuffer(wgpu::Device device,
+ size_t size,
+ wgpu::BufferUsage usage,
+ MapAtCreation mappedAtCreation)
+{
+ wgpu::BufferDescriptor descriptor;
+ descriptor.size = size;
+ descriptor.usage = usage;
+ descriptor.mappedAtCreation = mappedAtCreation == MapAtCreation::Yes;
+
+ mBuffer = device.CreateBuffer(&descriptor);
+
+ if (mappedAtCreation == MapAtCreation::Yes)
+ {
+ mMappedState = {wgpu::MapMode::Read | wgpu::MapMode::Write, 0, size};
+ }
+ else
+ {
+ mMappedState.reset();
+ }
+
+ return angle::Result::Continue;
+}
+
+angle::Result BufferHelper::mapImmediate(ContextWgpu *context,
+ wgpu::MapMode mode,
+ size_t offset,
+ size_t size)
+{
+ ASSERT(!mMappedState.has_value());
+
+ WGPUBufferMapAsyncStatus mapResult = WGPUBufferMapAsyncStatus_Unknown;
+
+ wgpu::BufferMapCallbackInfo callbackInfo;
+ callbackInfo.mode = wgpu::CallbackMode::WaitAnyOnly;
+ callbackInfo.callback = [](WGPUBufferMapAsyncStatus status, void *userdata) {
+ *static_cast<WGPUBufferMapAsyncStatus *>(userdata) = status;
+ };
+ callbackInfo.userdata = &mapResult;
+
+ wgpu::FutureWaitInfo waitInfo;
+ waitInfo.future = mBuffer.MapAsync(mode, offset, size, callbackInfo);
+
+ wgpu::Instance instance = context->getDisplay()->getInstance();
+ ANGLE_WGPU_TRY(context, instance.WaitAny(1, &waitInfo, -1));
+ ANGLE_WGPU_TRY(context, mapResult);
+
+ ASSERT(waitInfo.completed);
+
+ mMappedState = {mode, offset, size};
+
+ return angle::Result::Continue;
+}
+
+angle::Result BufferHelper::unmap()
+{
+ ASSERT(mMappedState.has_value());
+ mBuffer.Unmap();
+ mMappedState.reset();
+ return angle::Result::Continue;
+}
+
+uint8_t *BufferHelper::getMapWritePointer(size_t offset, size_t size) const
+{
+ ASSERT(mBuffer.GetMapState() == wgpu::BufferMapState::Mapped);
+ ASSERT(mMappedState.has_value());
+ ASSERT(mMappedState->offset <= offset);
+ ASSERT(mMappedState->offset + mMappedState->size >= offset + size);
+
+ void *mapPtr = mBuffer.GetMappedRange(offset, size);
+ ASSERT(mapPtr);
+
+ return static_cast<uint8_t *>(mapPtr);
+}
+
+const std::optional<BufferMapState> &BufferHelper::getMappedState() const
+{
+ return mMappedState;
+}
+
+bool BufferHelper::canMapForRead() const
+{
+ return (mMappedState.has_value() && (mMappedState->mode & wgpu::MapMode::Read)) ||
+ (mBuffer && (mBuffer.GetUsage() & wgpu::BufferUsage::MapRead));
+}
+
+bool BufferHelper::canMapForWrite() const
+{
+ return (mMappedState.has_value() && (mMappedState->mode & wgpu::MapMode::Write)) ||
+ (mBuffer && (mBuffer.GetUsage() & wgpu::BufferUsage::MapWrite));
+}
+
+wgpu::Buffer &BufferHelper::getBuffer()
+{
+ return mBuffer;
+}
+
+uint64_t BufferHelper::size() const
+{
+ return mBuffer ? mBuffer.GetSize() : 0;
+}
+
} // namespace webgpu
+} // namespace rx
diff --git a/src/libANGLE/renderer/wgpu/wgpu_helpers.h b/src/libANGLE/renderer/wgpu/wgpu_helpers.h
index 79783ddba6..7420da047a 100644
--- a/src/libANGLE/renderer/wgpu/wgpu_helpers.h
+++ b/src/libANGLE/renderer/wgpu/wgpu_helpers.h
@@ -15,6 +15,11 @@
#include "libANGLE/angletypes.h"
#include "libANGLE/renderer/wgpu/wgpu_utils.h"
+namespace rx
+{
+
+class ContextWgpu;
+
namespace webgpu
{
@@ -67,6 +72,56 @@ class ImageHelper
std::vector<QueuedDataUpload> mBufferQueue;
};
-} // namespace webgpu
+struct BufferMapState
+{
+ wgpu::MapMode mode;
+ size_t offset;
+ size_t size;
+};
+
+enum class MapAtCreation
+{
+ No,
+ Yes,
+};
+
+class BufferHelper : public angle::NonCopyable
+{
+ public:
+ BufferHelper();
+ ~BufferHelper();
+
+ bool valid() const { return mBuffer != nullptr; }
+ void reset();
+
+ angle::Result initBuffer(wgpu::Device device,
+ size_t size,
+ wgpu::BufferUsage usage,
+ MapAtCreation mappedAtCreation);
+
+ angle::Result mapImmediate(ContextWgpu *context,
+ wgpu::MapMode mode,
+ size_t offset,
+ size_t size);
+ angle::Result unmap();
+
+ uint8_t *getMapWritePointer(size_t offset, size_t size) const;
+
+ const std::optional<BufferMapState> &getMappedState() const;
+
+ bool canMapForRead() const;
+ bool canMapForWrite() const;
+
+ wgpu::Buffer &getBuffer();
+ uint64_t size() const;
+
+ private:
+ wgpu::Buffer mBuffer;
+
+ std::optional<BufferMapState> mMappedState;
+};
+
+} // namespace webgpu
+} // namespace rx
#endif // LIBANGLE_RENDERER_WGPU_WGPU_HELPERS_H_
diff --git a/src/libANGLE/renderer/wgpu/wgpu_utils.cpp b/src/libANGLE/renderer/wgpu/wgpu_utils.cpp
index fd243ad22d..af46c1266e 100644
--- a/src/libANGLE/renderer/wgpu/wgpu_utils.cpp
+++ b/src/libANGLE/renderer/wgpu/wgpu_utils.cpp
@@ -6,6 +6,49 @@
#include "libANGLE/renderer/wgpu/wgpu_utils.h"
+#include "libANGLE/renderer/wgpu/ContextWgpu.h"
+#include "libANGLE/renderer/wgpu/DisplayWgpu.h"
+
+namespace rx
+{
+
+namespace webgpu
+{
+ContextWgpu *GetImpl(const gl::Context *context)
+{
+ return GetImplAs<ContextWgpu>(context);
+}
+
+DisplayWgpu *GetDisplay(const gl::Context *context)
+{
+ ContextWgpu *contextWgpu = GetImpl(context);
+ return contextWgpu->getDisplay();
+}
+
+wgpu::Device GetDevice(const gl::Context *context)
+{
+ DisplayWgpu *display = GetDisplay(context);
+ return display->getDevice();
+}
+
+wgpu::Instance GetInstance(const gl::Context *context)
+{
+ DisplayWgpu *display = GetDisplay(context);
+ return display->getInstance();
+}
+
+bool IsError(wgpu::WaitStatus waitStatus)
+{
+ return waitStatus != wgpu::WaitStatus::Success;
+}
+
+bool IsError(WGPUBufferMapAsyncStatus mapBufferStatus)
+{
+ return mapBufferStatus != WGPUBufferMapAsyncStatus_Success;
+}
+
+} // namespace webgpu
+
namespace wgpu_gl
{
gl::LevelIndex getLevelIndex(webgpu::LevelIndex levelWgpu, gl::LevelIndex baseLevel)
@@ -66,3 +109,4 @@ wgpu::TextureDimension getWgpuTextureDimension(gl::TextureType glTextureType)
return dimension;
}
} // namespace gl_wgpu
+} // namespace rx
diff --git a/src/libANGLE/renderer/wgpu/wgpu_utils.h b/src/libANGLE/renderer/wgpu/wgpu_utils.h
index b094223b39..1514d8fb5b 100644
--- a/src/libANGLE/renderer/wgpu/wgpu_utils.h
+++ b/src/libANGLE/renderer/wgpu/wgpu_utils.h
@@ -13,9 +13,26 @@
#include "libANGLE/Error.h"
#include "libANGLE/angletypes.h"
-namespace webgpu
+#define ANGLE_WGPU_TRY(context, command) \
+ do \
+ { \
+ auto ANGLE_LOCAL_VAR = command; \
+ if (ANGLE_UNLIKELY(::rx::webgpu::IsError(ANGLE_LOCAL_VAR))) \
+ { \
+ (context)->handleError(GL_INVALID_OPERATION, "Internal WebGPU error.", __FILE__, \
+ ANGLE_FUNCTION, __LINE__); \
+ return angle::Result::Stop; \
+ } \
+ } while (0)
+
+namespace rx
{
+class ContextWgpu;
+class DisplayWgpu;
+
+namespace webgpu
+{
// WebGPU image level index.
using LevelIndex = gl::LevelIndexWrapper<uint32_t>;
@@ -27,6 +44,13 @@ enum class RenderPassClosureReason
EnumCount = InvalidEnum,
};
+ContextWgpu *GetImpl(const gl::Context *context);
+DisplayWgpu *GetDisplay(const gl::Context *context);
+wgpu::Device GetDevice(const gl::Context *context);
+wgpu::Instance GetInstance(const gl::Context *context);
+
+bool IsError(wgpu::WaitStatus waitStatus);
+bool IsError(WGPUBufferMapAsyncStatus mapBufferStatus);
} // namespace webgpu
namespace wgpu_gl
@@ -42,4 +66,6 @@ wgpu::TextureDimension getWgpuTextureDimension(gl::TextureType glTextureType);
wgpu::Extent3D getExtent3D(const gl::Extents &glExtent);
} // namespace gl_wgpu
+} // namespace rx
+
#endif // LIBANGLE_RENDERER_WGPU_WGPU_UTILS_H_
diff --git a/src/tests/gl_tests/RendererTest.cpp b/src/tests/gl_tests/RendererTest.cpp
index c5f2f14a7f..5e798cb8a3 100644
--- a/src/tests/gl_tests/RendererTest.cpp
+++ b/src/tests/gl_tests/RendererTest.cpp
@@ -10,6 +10,7 @@
// meant to be using the D3D9 renderer.
#include "test_utils/ANGLETest.h"
+#include "test_utils/gl_raii.h"
#include "util/test_utils.h"
#include "common/string_utils.h"
@@ -161,6 +162,34 @@ TEST_P(RendererTest, SimpleOperation)
ASSERT_GL_NO_ERROR();
}
+// Perform a simple buffer operation.
+TEST_P(RendererTest, BufferData)
+{
+ constexpr size_t kBufferSize = 1024;
+ std::array<uint8_t, kBufferSize> data;
+ for (size_t i = 0; i < kBufferSize; i++)
+ {
+ data[i] = static_cast<uint8_t>(i);
+ }
+
+ // All at once in the glBufferData call
+ {
+ GLBuffer buffer;
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+
+ glBufferData(GL_ARRAY_BUFFER, 1024, data.data(), GL_STATIC_DRAW);
+ }
+
+ // Set data with sub data
+ {
+ GLBuffer buffer;
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+
+ glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, kBufferSize, data.data());
+ }
+}
+
// Select configurations (e.g. which renderer, which GLES major version) these tests should be run
// against.
// TODO(http://anglebug.com/8485): move ES2_WEBGPU to the definition of ANGLE_ALL_TEST_PLATFORMS_ES2