Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WebGPU] Support tier1 level argument buffers #8275

Conversation

mwyrzykowski
Copy link
Contributor

@mwyrzykowski mwyrzykowski commented Jan 6, 2023

8e36095

[WebGPU] Support tier1 level argument buffers
https://bugs.webkit.org/show_bug.cgi?id=250123
<radar://103905011>

Reviewed by Myles C. Maxfield.

Support Tier1 argument buffers which are limited to
pre-A13 devices and some Intel Macs.

Tested on a pre-A13 iPad Pro.

* Source/WebGPU/WebGPU/BindGroup.mm:
(WebGPU::sizeOfEntries):
(WebGPU::Device::createBindGroup):
Support tier1 ABs.

* Source/WebGPU/WebGPU/BindGroupLayout.h:
(WebGPU::BindGroupLayout::create):
Simplify create function.

* Source/WebGPU/WebGPU/BindGroupLayout.mm:
(WebGPU::createArgumentDescriptor):
(WebGPU::addDescriptor):
(WebGPU::Device::createBindGroupLayout):
(WebGPU::BindGroupLayout::BindGroupLayout):
(WebGPU::BindGroupLayout::encodedLength const):
Support tier1 ABs.

* Source/WebGPU/WebGPU/RenderPipeline.mm:
(WebGPU::createEntryFromStructMember):
(WebGPU::RenderPipeline::getBindGroupLayout):
Call Device::createBindLayout instead and pass some additional
information to be compatible with Tier1 ABs.

Canonical link: https://commits.webkit.org/258651@main

d188141

Misc iOS, tvOS & watchOS macOS Linux Windows
βœ… πŸ§ͺ style βœ… πŸ›  ios βœ… πŸ›  mac βœ… πŸ›  wpe πŸ’₯ πŸ›  πŸ§ͺ win
βœ… πŸ›  ios-sim βœ… πŸ›  mac-AS-debug βœ… πŸ›  gtk βœ… πŸ›  wincairo
βœ… πŸ§ͺ webkitperl βœ… πŸ§ͺ ios-wk2 βœ… πŸ§ͺ api-mac βœ… πŸ§ͺ gtk-wk2
  πŸ§ͺ api-ios βœ… πŸ§ͺ mac-wk1 ❌ πŸ§ͺ api-gtk
❌ πŸ›  πŸ§ͺ jsc βœ… πŸ›  tv βœ… πŸ§ͺ mac-wk2 βœ… πŸ›  jsc-armv7
βœ… πŸ›  πŸ§ͺ jsc-arm64 βœ… πŸ›  tv-sim βœ… πŸ§ͺ mac-AS-debug-wk2 βœ… πŸ§ͺ jsc-armv7-tests
βœ… πŸ›  watch βœ… πŸ§ͺ mac-wk2-stress βœ… πŸ›  jsc-mips
βœ… πŸ›  πŸ§ͺ merge βœ… πŸ›  watch-sim βœ… πŸ§ͺ jsc-mips-tests

@mwyrzykowski mwyrzykowski self-assigned this Jan 6, 2023
@mwyrzykowski mwyrzykowski added the WebGPU For bugs in WebGPU label Jan 6, 2023
@@ -109,21 +109,28 @@ static bool isPresent(const WGPUStorageTextureBindingLayout& storageTexture)
return nil;

UNUSED_PARAM(storageTexture);
auto descriptor = [MTLArgumentDescriptor new];
auto descriptor = [MTLArgumentDescriptor argumentDescriptor];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change isn't needed, it could be reverted.

@webkit-ews-buildbot webkit-ews-buildbot added the merging-blocked Applied to prevent a change from being merged label Jan 6, 2023
@mwyrzykowski mwyrzykowski removed the merging-blocked Applied to prevent a change from being merged label Jan 6, 2023
@mwyrzykowski mwyrzykowski force-pushed the eng/WebGPU-Support-tier1-level-argument-buffers branch from e9ea635 to ca18423 Compare January 6, 2023 04:51
@@ -41,13 +41,9 @@ class Device;
class BindGroupLayout : public WGPUBindGroupLayoutImpl, public RefCounted<BindGroupLayout> {
WTF_MAKE_FAST_ALLOCATED;
public:
static Ref<BindGroupLayout> create(id<MTLArgumentEncoder> vertexArgumentEncoder, id<MTLArgumentEncoder> fragmentArgumentEncoder, id<MTLArgumentEncoder> computeArgumentEncoder)
static Ref<BindGroupLayout> create(HashMap<uint32_t, WGPUShaderStageFlags>&& stageMapTable, id<MTLArgumentEncoder> vertexArgumentEncoder = nil, id<MTLArgumentEncoder> fragmentArgumentEncoder = nil, id<MTLArgumentEncoder> computeArgumentEncoder = nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not pass as an array of id<MTLArgumentEncoder>s instead of individually? (And instead of m_vertexArgumentEncoder, access would be via m_argumentEncoder[vertex])

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is possible but I would need to make vertex / fragment / compute accessible via the BindGroupLayout too, currently they are only defined in BindGroup.mm

@mwyrzykowski mwyrzykowski force-pushed the eng/WebGPU-Support-tier1-level-argument-buffers branch from ca18423 to 8277c6f Compare January 6, 2023 19:23
@mwyrzykowski mwyrzykowski force-pushed the eng/WebGPU-Support-tier1-level-argument-buffers branch from 8277c6f to d06450e Compare January 6, 2023 19:45
Vector<BindableResource> resources;
#if HAVE(TIER2_ARGUMENT_BUFFERS)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, so much red!

Ref<BindGroup> Device::createBindGroup(const WGPUBindGroupDescriptor& descriptor)
{
if (descriptor.nextInChain)
return BindGroup::createInvalid(*this);

constexpr WGPUShaderStage shaderStage[] = { WGPUShaderStage_Vertex, WGPUShaderStage_Fragment, WGPUShaderStage_Compute };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like your opinion about something. On a previous review, Kimmo suggested considering the WGPU types as external types, only to be used at the API boundary of the framework. Just like how we have WGPUBuffer as an API type, but internally we have WebGPU::Buffer, we could extend that relationship to all WGPU types. The "binding" code to turn all WGPU types into their corresponding WebGPU:: types would be generated code, driven by IDL as a custom build step.

What do you think about the tradeoff of having cleaner internal/external boundaries, vs the added infrastructure (and potential runtime cost?) of transforming a bunch of types into different types that have the same expressivity?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this makes a lot of sense since if the external (WGPU) types change in any form (renames or values change), we do not want to have a lot of compilation or runtime breakage throughout our code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll make this change prior to merging


return BindGroup::create(argumentBuffer[0], argumentBuffer[1], argumentBuffer[2], WTFMove(resources), *this);
id<MTLArgumentEncoder> argumentEncoder[] = { bindGroupLayout.vertexArgumentEncoder(), bindGroupLayout.fragmentArgumentEncoder(), bindGroupLayout.computeArgumentEncoder() };
for (size_t i = 0; i < shaderStageLength; ++i) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you feel about naming these values of i in an enum, and doing this in a lambda instead of a loop? EnumeratedArray is a pretty elegant thing to use for situations like these.

enum class ShaderType {
    Vertex,
    Fragment,
    Compute
};
EnumeratedArray<ShaderType, id<MTLArgumentEncoder>, ShaderType::Compute> argumentEncoders;
auto foo = [](ShaderType type) {
    ... argumentEncoders[type] ...
}
foo(ShaderType::Vertex);
foo(ShaderType::Fragment);
foo(ShaderType::Compute);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using EnumeratedArray makes sense, I'm attempting to apply the suggestion of using EnumeratedArray without using the lambdas since it doubles the code lines of the first for loop which I think impacts readability.

ASSERT_NOT_REACHED();
return BindGroup::createInvalid(*this);
auto stages = bindGroupLayout.stagesForBinding(entry.binding);
for (size_t currentStage = 0; currentStage < shaderStageLength; ++currentStage) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(ditto, if you decide that it's a good idea)

Comment on lines 92 to 118
if (bufferIsPresent) {
id<MTLBuffer> buffer = WebGPU::fromAPI(entry.buffer).buffer();
if (entry.offset > buffer.length)
return BindGroup::createInvalid(*this);

[argumentEncoder[currentStage] setBuffer:buffer offset:entry.offset atIndex:index++];
} else if (samplerIsPresent) {
id<MTLSamplerState> sampler = WebGPU::fromAPI(entry.sampler).samplerState();
[argumentEncoder[currentStage] setSamplerState:sampler atIndex:index++];
} else if (textureViewIsPresent) {
id<MTLTexture> texture = WebGPU::fromAPI(entry.textureView).texture();
[argumentEncoder[currentStage] setTexture:texture atIndex:index++];
resources.append({ texture, MTLResourceUsageRead, renderStage });
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks pretty nice

}
}

return BindGroup::create(vertexArgumentBuffer, fragmentArgumentBuffer, computeArgumentBuffer, WTFMove(resources), *this);
constexpr int vertex = 0, fragment = 1, compute = 2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, the enum would save you from having to do this

@@ -488,6 +488,32 @@ static MTLVertexStepFunction stepFunction(WGPUVertexStepMode stepMode)

RenderPipeline::~RenderPipeline() = default;

#if HAVE(METAL_BUFFER_BINDING_REFLECTION)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright

@mwyrzykowski mwyrzykowski force-pushed the eng/WebGPU-Support-tier1-level-argument-buffers branch from d06450e to 16113e0 Compare January 8, 2023 19:45
@mwyrzykowski mwyrzykowski force-pushed the eng/WebGPU-Support-tier1-level-argument-buffers branch from 16113e0 to d188141 Compare January 8, 2023 20:53
@mwyrzykowski mwyrzykowski added the merge-queue Applied to send a pull request to merge-queue label Jan 9, 2023
https://bugs.webkit.org/show_bug.cgi?id=250123
<radar://103905011>

Reviewed by Myles C. Maxfield.

Support Tier1 argument buffers which are limited to
pre-A13 devices and some Intel Macs.

Tested on a pre-A13 iPad Pro.

* Source/WebGPU/WebGPU/BindGroup.mm:
(WebGPU::sizeOfEntries):
(WebGPU::Device::createBindGroup):
Support tier1 ABs.

* Source/WebGPU/WebGPU/BindGroupLayout.h:
(WebGPU::BindGroupLayout::create):
Simplify create function.

* Source/WebGPU/WebGPU/BindGroupLayout.mm:
(WebGPU::createArgumentDescriptor):
(WebGPU::addDescriptor):
(WebGPU::Device::createBindGroupLayout):
(WebGPU::BindGroupLayout::BindGroupLayout):
(WebGPU::BindGroupLayout::encodedLength const):
Support tier1 ABs.

* Source/WebGPU/WebGPU/RenderPipeline.mm:
(WebGPU::createEntryFromStructMember):
(WebGPU::RenderPipeline::getBindGroupLayout):
Call Device::createBindLayout instead and pass some additional
information to be compatible with Tier1 ABs.

Canonical link: https://commits.webkit.org/258651@main
@webkit-commit-queue webkit-commit-queue force-pushed the eng/WebGPU-Support-tier1-level-argument-buffers branch from d188141 to 8e36095 Compare January 9, 2023 07:08
@webkit-commit-queue
Copy link
Collaborator

Committed 258651@main (8e36095): https://commits.webkit.org/258651@main

Reviewed commits have been landed. Closing PR #8275 and removing active labels.

@webkit-commit-queue webkit-commit-queue merged commit 8e36095 into WebKit:main Jan 9, 2023
@webkit-commit-queue webkit-commit-queue removed the merge-queue Applied to send a pull request to merge-queue label Jan 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
WebGPU For bugs in WebGPU
Projects
None yet
6 participants