Changeset 224065 in webkit


Ignore:
Timestamp:
Oct 26, 2017 4:32:10 PM (6 years ago)
Author:
mmaxfield@apple.com
Message:

Demonstrate a possible structure of the WebGPU API
https://bugs.webkit.org/show_bug.cgi?id=178874

Reviewed by Dean Jackson.

Over the past few weeks, we've been putting together an example showing that a WebGPU API
which has implicit barriers can work on all three low-level graphics APIs. We've implemented
it on top of Vulkan first, because this is the API which has the strictest requirements and
is most difficult to use.

With this API, this is a valid WebGPU snippet:

auto device = WebGPU::Device::create(hInstance, hWnd);
auto& commandQueue = device->getCommandQueue();
auto& renderState = device->getRenderState(vertexShader, "main", fragmentShader, "main", { }, { }, { }, nullptr);

… later, in the draw() function …

auto renderPass = commandQueue->createRenderPass(nullptr);
renderPass->setRenderState(renderState);
renderPass->setViewport(0, 0, width, height);
renderPass->setScissorRect(0, 0, width, height);
renderPass->draw(3);
commandQueue->commitRenderPass(std::move(renderPass));
commandQueue->present();

This snippet doesn’t hook up any vertex attributes or resources, which means the vertex
shader has to say something like ({vec4(…), vec4(…), vec4(…)})[gl_VertexIndex]. It also
passes in “nullptr” when creating the render pass, which means “render to the screen, rather
than to a frame buffer.” You can also see that it doesn’t attach any resources to the draw
call.

In Direct3D 12 and Vulkan, resources are bound in sets, rather than individually. For
example, a set might contain two uniform buffers, a texture, and another uniform buffer. At
draw time, you swap in whole sets of resources with a single call. A shader invocation can
access a collection of sets. Because all shader resource accesses are indirected through
these sets, the shape of these sets needs to be supplied at the time you compile the render
state. Here is a snippet which bounds a single set which contains a uniform buffer and a
texture:

auto buffer = device->getBuffer(bufferInitialContents);
auto texture = device->getTexture(buffer width, height, WebGPU::PixelFormat::RGBA8, textureInitialContents);
One resource set, which holds a single uniform buffer object and a single texture
auto& renderState = device->getRenderState(vertexShader, "main", fragmentShader, "main", { }, { }, { { WebGPU::ResourceType::UniformBufferObject, WebGPU::ResourceType::Texture } }, nullptr);

… later, in the draw() function …

auto renderPass = commandQueue->createRenderPass(nullptr);
renderPass->setRenderState(renderState);
renderPass->setResources(0, { WebGPU::UniformBufferObjectReference(buffer.get()), WebGPU::TextureReference(texture.get()) });

renderPass->draw(3);
commandQueue->commitRenderPass(std::move(renderPass));
commandQueue->present();

The first argument to the setResources() call identifies which set to populate with the supplied resources.

One tenant of the low-level graphics APIs is that, if you’ve enabled double buffering (or
triple buffering), the GPU is executing one frame at the same time you are recording the
next frame. This often means that you need duplicate resources so the CPU and GPU don’t step
on each other’s toes. However, platforms have platform-specific requirements about whether
or not they can be double / triple buffered, and we don’t want to expose this to the Web for
fear of badly-authored programs.

To solve this, resources are reference counted, and the return type of getBuffer() is an
RAII type called BufferHolder which increments and decrements the reference count
automatically. The reference count is also incremented and decremented when the GPU is using
the resource in a Pass. When the reference count reaches 0, the resource isn’t destroyed;
instead, it’s simply moved to a “free list” which getBuffer() may pull from. Therefore,
applications don’t need to know whether the frame buffer is double buffered or triple
buffered; they can just getBuffer() each frame, and the correct number of buffers will be
created and recycled.

{

auto buffer = device->getBuffer(bufferSize); These get recycled
… populate the buffer …
auto renderPass = commandQueue->createRenderPass(nullptr);
renderPass->setRenderState(renderState);
renderPass->setResources(0, { WebGPU::UniformBufferObjectReference(buffer.get()) });

renderPass->draw(…);
commandQueue->commitRenderPass(std::move(renderPass));

}
commandQueue->present();

In Direct3D and Vulkan, vertex buffers and index buffers are not part of the resource sets
mentioned above. Instead, you tell the render state about the shape of the vertex and index
buffers, and you swap them out independently in the draw loop. Metal and Vulkan have almost
identical API to specify this shape of the vertex buffers, so I’ve mostly copied it. In this
example, we have two vertex attributes, a vec2 and a vec3, which both come from the same
buffer:

{ Attribute format, offset within stride, buffer to pull from }
std::vector<WebGPU::RenderState::VertexAttribute> vertexAttributes = { {WebGPU::RenderState::VertexFormat::Float2, 0, 0}, {WebGPU::RenderState::VertexFormat::Float3, sizeof(float) * 2, 0} };
A single vertex buffer, with a stride of 5 floats
auto& renderState = device->getRenderState(vertexShader, "main", fragmentShader, "main", { sizeof(float) * 5 }, vertexAttributes, resourceTypes, nullptr);

… later, in the draw() function …

auto renderPass = commandQueue->createRenderPass(nullptr);
renderPass->setRenderState(renderState);
renderPass->setVertexAttributeBuffers({ vertexBuffer.get() }); The one vertex buffer which both attributes pull from
renderPass->setResources(…);

renderPass->draw(…);
commandQueue->commitRenderPass(std::move(renderPass));
commandQueue->present();

You can also tell the RenderState about how many render targets you have and their formats,
and then when you create the RenderPass, you specify the specific textures you want to
render into.

std::vector<WebGPU::PixelFormat> colorPixelFormats = { WebGPU::PixelFormat::RGBA8, WebGPU::PixelFormat::RGBA8 }; Two render targets, with these formats
auto& renderState = device->getRenderState(vertexShader, "main", fragmentShader, "main", vertexBufferStrides, vertexAttributes, resourceTypes, &colorPixelFormats);

… later, in the draw() function …

std::vector<std::reference_wrapper<WebGPU::Texture>> destinationTextures = { texture1->get(), texture2->get() };
auto renderPass = commandQueue->createRenderPass(&destinationTextures);
renderPass->setRenderState(renderState);

renderPass->draw(…);
commandQueue->commitRenderPass(std::move(renderPass));

Now, draw one of the textures to the screen. Note that no synchronization is necessary here!
auto renderPass = commandQueue->createRenderPass(nullptr);
renderPass->setRenderState(renderState2);
renderPass->setResources(0, { WebGPU:: TextureReference(texture1.get()) });

renderPass->draw(…);
commandQueue->commitRenderPass(std::move(renderPass));
commandQueue->present();

Just like how in Metal has Render Encoders and Compute Encoders, WebGPU has RenderPasses
and ComputePasses.

auto& computeState = device->getComputeState(computeShader, "main", resourceTypes);

auto computePass = commandQueue->createComputePass();
computePass->setComputeState(computeState);
computePass->setResources(0, resources);
computePass->dispatch(width, height, depth);
commandQueue->commitComputePass(std::move(computePass));

Now, draw the resources we just computed. Note that no synchronization is necessary here!
auto renderPass = commandQueue->createRenderPass(nullptr);
renderPass->setRenderState(renderState);
renderPass->setResources(0, resources });

renderPass->draw(…);
commandQueue->commitRenderPass(std::move(renderPass));
commandQueue->present();

There are also two other types of passes: one that corresponds to a Metal blit encoder, and
one that allows the CPU to change the contents of GPU buffers and textures. This last kind
of pass is a little interesting: you can’t just change the contents of a buffer at any time
you feel like it, because that resource might be in use by the GPU. Therefore, we need to do
the same kind of synchronization that we already do at render pass boundaries.

In addition, both Vulkan and Direct3D have a concept of a memory heap. A resource might
exist inside a heap which is fast, but invisible from the CPU, or in a heap which is slow,
but visible by the CPU. Certain operations are not possible from some types of images (e.g.
non-tiled textures may not be able to be sampled from). The usual way to get around this
problem is to have two resources: a slow staging resource which the CPU can see, and a fast
resource which the CPU can’t see. Uploading data is a two-pass algorithm, where the CPU
memcpy()s into the slow staging resource, and then a blit command is enqueued on the GPU to
copy the contents of the staging resource to the real resource. This requires that the
upload have access to the commandQueue so it can possibly enqueue a blit between the staging
and real resources. Therefore, a pass is the right level of abstraction for these facilities.

std::queue<boost::unique_future<std::vector<uint8_t>>> futureQueue; Promises for data downloads from the GPU

… later, in the draw() function …

See if any of the previously-enqueued downloads are finished
while (!futureQueue.empty() && futureQueue.front(). has_value()) {

std::vector<uint8_t>& data = futureQueue.front().get();
Use the downloaded data
futureQueue.pop();

}

auto hostAccessPass = commandQueue->createHostAccessPass();
hostAccessPass->overwriteBuffer(buffer->get(), bufferContents); Upload data to a resource

futureQueue.emplace(hostAccessPass->getBufferContents(buffer->get()));
commandQueue->commitHostAccessPass(std::move(hostAccessPass));

You can also issue copy commands between resources entirely on the GPU:

auto blitPass = commandQueue->createBlitPass();
blitPass->copyTexture(source->get(), destination->get(), sourceX, sourceY, destinationX, destinationY, width, height);
commandQueue->commitBlitPass(std::move(blitPass));

  • Scripts/webkitpy/style/checker.py:
  • WebGPUAPIStructure/Example/Example.cpp: Added.

(readFile):
(drawWebGPU):
(wWinMain):
(MyRegisterClass):
(InitInstance):
(WndProc):

  • WebGPUAPIStructure/Example/Example.h: Added.
  • WebGPUAPIStructure/Example/Example.ico: Added.
  • WebGPUAPIStructure/Example/Example.rc: Added.
  • WebGPUAPIStructure/Example/Example.vcxproj: Added.
  • WebGPUAPIStructure/Example/Example.vcxproj.filters: Added.
  • WebGPUAPIStructure/Example/Example.vcxproj.user: Added.
  • WebGPUAPIStructure/Example/resource.h: Added.
  • WebGPUAPIStructure/Example/small.ico: Added.
  • WebGPUAPIStructure/Example/stdafx.cpp: Added.
  • WebGPUAPIStructure/Example/stdafx.h: Added.
  • WebGPUAPIStructure/Example/targetver.h: Added.
  • WebGPUAPIStructure/WebGPU-Common/WebGPU-Common.vcxproj: Added.
  • WebGPUAPIStructure/WebGPU-Common/WebGPU-Common.vcxproj.filters: Added.
  • WebGPUAPIStructure/WebGPU-Common/WebGPU.cpp: Added.

(WebGPU::BufferHolder::BufferHolder):
(WebGPU::BufferHolder::~BufferHolder):
(WebGPU::TextureHolder::TextureHolder):
(WebGPU::TextureHolder::~TextureHolder):
(WebGPU::SamplerHolder::SamplerHolder):
(WebGPU::SamplerHolder::~SamplerHolder):

  • WebGPUAPIStructure/WebGPU-Common/WebGPU.h: Added.

(WebGPU::Queue::~Queue):
(WebGPU::RenderState::~RenderState):
(WebGPU::ComputeState::~ComputeState):
(WebGPU::Buffer::~Buffer):
(WebGPU::Texture::~Texture):
(WebGPU::Sampler::~Sampler):
(WebGPU::TextureReference::TextureReference):
(WebGPU::TextureReference::get const):
(WebGPU::SamplerReference::SamplerReference):
(WebGPU::SamplerReference::get const):
(WebGPU::UniformBufferObjectReference::UniformBufferObjectReference):
(WebGPU::UniformBufferObjectReference::get const):
(WebGPU::ShaderStorageBufferObjectReference::ShaderStorageBufferObjectReference):
(WebGPU::ShaderStorageBufferObjectReference::get const):
(WebGPU::RenderPass::~RenderPass):
(WebGPU::ComputePass::~ComputePass):
(WebGPU::BlitPass::~BlitPass):
(WebGPU::HostAccessPass::~HostAccessPass):
(WebGPU::BufferHolder::get):
(WebGPU::TextureHolder::get):
(WebGPU::SamplerHolder::get):
(WebGPU::Device::~Device):

  • WebGPUAPIStructure/WebGPU-Vulkan/BlitPassImpl.cpp: Added.

(WebGPU::BlitPassImpl::BlitPassImpl):
(WebGPU::BlitPassImpl::copyTexture):

  • WebGPUAPIStructure/WebGPU-Vulkan/BlitPassImpl.h: Added.
  • WebGPUAPIStructure/WebGPU-Vulkan/BufferImpl.cpp: Added.

(WebGPU::BufferImpl::BufferImpl):
(WebGPU::BufferImpl::decrementReferenceCount):

  • WebGPUAPIStructure/WebGPU-Vulkan/BufferImpl.h: Added.

(WebGPU::BufferImpl::getBuffer const):
(WebGPU::BufferImpl::getDeviceMemory const):
(WebGPU::BufferImpl::incrementReferenceCount):
(WebGPU::BufferImpl::getLength const):

  • WebGPUAPIStructure/WebGPU-Vulkan/ComputePassImpl.cpp: Added.

(WebGPU::ComputePassImpl::ComputePassImpl):
(WebGPU::ComputePassImpl::setComputeState):
(WebGPU::ComputePassImpl::setResources):
(WebGPU::ComputePassImpl::dispatch):

  • WebGPUAPIStructure/WebGPU-Vulkan/ComputePassImpl.h: Added.
  • WebGPUAPIStructure/WebGPU-Vulkan/ComputeStateImpl.cpp: Added.

(WebGPU::ComputeStateImpl::ComputeStateImpl):

  • WebGPUAPIStructure/WebGPU-Vulkan/ComputeStateImpl.h: Added.

(WebGPU::ComputeStateImpl::getPipeline const):
(WebGPU::ComputeStateImpl::getPipelineLayout const):
(WebGPU::ComputeStateImpl::getDescriptorSetLayouts const):

  • WebGPUAPIStructure/WebGPU-Vulkan/DeviceImpl.cpp: Added.

(WebGPU::Device::create):
(WebGPU::convertPixelFormat):
(WebGPU::convertFormat):
(WebGPU::debugReport):
(WebGPU::DeviceImpl::DeviceImpl):
(WebGPU::DeviceImpl::getCommandQueue):
(WebGPU::DeviceImpl::prepareShader):
(WebGPU::DeviceImpl::createPipelineLayout):
(WebGPU::DeviceImpl::createCompatibleRenderPass):
(WebGPU::convertVertexFormat):
(WebGPU::DeviceImpl::getRenderState):
(WebGPU::DeviceImpl::getComputeState):
(WebGPU::DeviceImpl::getBuffer):
(WebGPU::DeviceImpl::returnBuffer):
(WebGPU::DeviceImpl::getTexture):
(WebGPU::DeviceImpl::returnTexture):
(WebGPU::DeviceImpl::getSampler):
(WebGPU::DeviceImpl::returnSampler):
(WebGPU::DeviceImpl::~DeviceImpl):

  • WebGPUAPIStructure/WebGPU-Vulkan/DeviceImpl.h: Added.

(WebGPU::DeviceImpl::UniqueDebugReportCallbackEXT::UniqueDebugReportCallbackEXT):
(WebGPU::DeviceImpl::UniqueDebugReportCallbackEXT::operator=):
(WebGPU::DeviceImpl::UniqueDebugReportCallbackEXT::~UniqueDebugReportCallbackEXT):
(WebGPU::DeviceImpl::UniqueDebugReportCallbackEXT::destroy):
(WebGPU::DeviceImpl::TextureParameters::operator== const):
(WebGPU::DeviceImpl::TextureParametersHash::operator() const):

  • WebGPUAPIStructure/WebGPU-Vulkan/HostAccessPassImpl.cpp: Added.

(WebGPU::HostAccessPassImpl::HostAccessPassImpl):
(WebGPU::HostAccessPassImpl::overwriteBuffer):
(WebGPU::HostAccessPassImpl::getBufferContents):
(WebGPU::HostAccessPassImpl::execute):

  • WebGPUAPIStructure/WebGPU-Vulkan/HostAccessPassImpl.h: Added.

(WebGPU::HostAccessPassImpl::getFinishedEvent const):

  • WebGPUAPIStructure/WebGPU-Vulkan/PassImpl.cpp: Added.

(WebGPU::PassImpl::PassImpl):
(WebGPU::ResourceVisitor::operator()):
(WebGPU::ResourceVisitor::getBindings const):
(WebGPU::ResourceVisitor::releaseWriteDescriptorSets):
(WebGPU::ResourceVisitor::getDescriptorImageInfos const):
(WebGPU::ResourceVisitor::getDescriptorBufferInfos const):
(WebGPU::ResourceVisitor::getBuffers const):
(WebGPU::ResourceVisitor::getTextures const):
(WebGPU::ResourceVisitor::getSamplers const):
(WebGPU::ResourceVisitor::getImageCount const):
(WebGPU::ResourceVisitor::getSamplerCount const):
(WebGPU::ResourceVisitor::getUniformBufferCount const):
(WebGPU::ResourceVisitor::getStorageBufferCount const):
(WebGPU::PassImpl::setResources):
(WebGPU::PassImpl::insertBuffer):
(WebGPU::PassImpl::insertTexture):
(WebGPU::PassImpl::insertSampler):

  • WebGPUAPIStructure/WebGPU-Vulkan/PassImpl.h: Added.

(WebGPU::PassImpl::getCommandBuffer const):
(WebGPU::PassImpl::iterateBuffers):
(WebGPU::PassImpl::iterateTextures):
(WebGPU::PassImpl::ResourceReference::ResourceReference):
(WebGPU::PassImpl::ResourceReference::~ResourceReference):
(WebGPU::PassImpl::ResourceReference::operator=):
(WebGPU::PassImpl::ResourceReference::operator== const):
(WebGPU::PassImpl::ResourceReference::get const):
(WebGPU::PassImpl::ResourceReference::release):
(WebGPU::PassImpl::ResourceReferenceHash::operator() const):

  • WebGPUAPIStructure/WebGPU-Vulkan/QueueImpl.cpp: Added.

(WebGPU::QueueImpl::QueueImpl):
(WebGPU::QueueImpl::prepareCurrentFrame):
(WebGPU::QueueImpl::createSpecificRenderPass):
(WebGPU::QueueImpl::createFramebuffer):
(WebGPU::QueueImpl::createRenderPass):
(WebGPU::QueueImpl::commitRenderPass):
(WebGPU::QueueImpl::createComputePass):
(WebGPU::QueueImpl::commitComputePass):
(WebGPU::QueueImpl::createBlitPass):
(WebGPU::QueueImpl::commitBlitPass):
(WebGPU::QueueImpl::createHostAccessPass):
(WebGPU::QueueImpl::commitHostAccessPass):
(WebGPU::QueueImpl::present):
(WebGPU::QueueImpl::commitPass):
(WebGPU::QueueImpl::synchronizeResources):
(WebGPU::QueueImpl::~QueueImpl):

  • WebGPUAPIStructure/WebGPU-Vulkan/QueueImpl.h: Added.
  • WebGPUAPIStructure/WebGPU-Vulkan/RenderPassImpl.cpp: Added.

(WebGPU::RenderPassImpl::RenderPassImpl):
(WebGPU::RenderPassImpl::setRenderState):
(WebGPU::RenderPassImpl::setVertexAttributeBuffers):
(WebGPU::RenderPassImpl::setResources):
(WebGPU::RenderPassImpl::setViewport):
(WebGPU::RenderPassImpl::setScissorRect):
(WebGPU::RenderPassImpl::draw):

  • WebGPUAPIStructure/WebGPU-Vulkan/RenderPassImpl.h: Added.
  • WebGPUAPIStructure/WebGPU-Vulkan/RenderStateImpl.cpp: Added.

(WebGPU::RenderStateImpl::RenderStateImpl):

  • WebGPUAPIStructure/WebGPU-Vulkan/RenderStateImpl.h: Added.

(WebGPU::RenderStateImpl::getPipeline const):
(WebGPU::RenderStateImpl::getPipelineLayout const):
(WebGPU::RenderStateImpl::getDescriptorSetLayouts const):

  • WebGPUAPIStructure/WebGPU-Vulkan/SamplerImpl.cpp: Added.

(WebGPU::SamplerImpl::SamplerImpl):
(WebGPU::SamplerImpl::decrementReferenceCount):

  • WebGPUAPIStructure/WebGPU-Vulkan/SamplerImpl.h: Added.

(WebGPU::SamplerImpl::getSampler):
(WebGPU::SamplerImpl::incrementReferenceCount):
(WebGPU::SamplerImpl::getFilter):
(WebGPU::SamplerImpl::getMipmapMode):
(WebGPU::SamplerImpl::getAddressMode):

  • WebGPUAPIStructure/WebGPU-Vulkan/TextureImpl.cpp: Added.

(WebGPU::TextureImpl::TextureImpl):
(WebGPU::TextureImpl::decrementReferenceCount):

  • WebGPUAPIStructure/WebGPU-Vulkan/TextureImpl.h: Added.

(WebGPU::TextureImpl::getImage const):
(WebGPU::TextureImpl::getImageView const):
(WebGPU::TextureImpl::getFormat const):
(WebGPU::TextureImpl::incrementReferenceCount):
(WebGPU::TextureImpl::getWidth const):
(WebGPU::TextureImpl::getHeight const):
(WebGPU::TextureImpl::getTransferredToGPU const):
(WebGPU::TextureImpl::setTransferredToGPU):

  • WebGPUAPIStructure/WebGPU-Vulkan/WebGPU-Vulkan.vcxproj: Added.
  • WebGPUAPIStructure/WebGPU-Vulkan/WebGPU-Vulkan.vcxproj.filters: Added.
  • WebGPUAPIStructure/WebGPU.sln: Added.
Location:
trunk/Tools
Files:
47 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r224057 r224065  
     12017-10-26  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        Demonstrate a possible structure of the WebGPU API
     4        https://bugs.webkit.org/show_bug.cgi?id=178874
     5
     6        Reviewed by Dean Jackson.
     7
     8        Over the past few weeks, we've been putting together an example showing that a WebGPU API
     9        which has implicit barriers can work on all three low-level graphics APIs. We've implemented
     10        it on top of Vulkan first, because this is the API which has the strictest requirements and
     11        is most difficult to use.
     12
     13        With this API, this is a valid WebGPU snippet:
     14
     15        auto device = WebGPU::Device::create(hInstance, hWnd);
     16        auto& commandQueue = device->getCommandQueue();
     17        auto& renderState = device->getRenderState(vertexShader, "main", fragmentShader, "main", { }, { }, { }, nullptr);
     18       
     19        … later, in the draw() function …
     20       
     21        auto renderPass = commandQueue->createRenderPass(nullptr);
     22        renderPass->setRenderState(renderState);
     23        renderPass->setViewport(0, 0, width, height);
     24        renderPass->setScissorRect(0, 0, width, height);
     25        renderPass->draw(3);
     26        commandQueue->commitRenderPass(std::move(renderPass));
     27        commandQueue->present();
     28
     29        This snippet doesn’t hook up any vertex attributes or resources, which means the vertex
     30        shader has to say something like ({vec4(…), vec4(…), vec4(…)})[gl_VertexIndex]. It also
     31        passes in “nullptr” when creating the render pass, which means “render to the screen, rather
     32        than to a frame buffer.” You can also see that it doesn’t attach any resources to the draw
     33        call.
     34
     35        In Direct3D 12 and Vulkan, resources are bound in sets, rather than individually. For
     36        example, a set might contain two uniform buffers, a texture, and another uniform buffer. At
     37        draw time, you swap in whole sets of resources with a single call. A shader invocation can
     38        access a collection of sets. Because all shader resource accesses are indirected through
     39        these sets, the shape of these sets needs to be supplied at the time you compile the render
     40        state. Here is a snippet which bounds a single set which contains a uniform buffer and a
     41        texture:
     42
     43        auto buffer = device->getBuffer(bufferInitialContents);
     44        auto texture = device->getTexture(buffer width, height, WebGPU::PixelFormat::RGBA8, textureInitialContents);
     45        // One resource set, which holds a single uniform buffer object and a single texture
     46        auto& renderState = device->getRenderState(vertexShader, "main", fragmentShader, "main", { }, { }, { { WebGPU::ResourceType::UniformBufferObject, WebGPU::ResourceType::Texture } }, nullptr);
     47       
     48        … later, in the draw() function …
     49       
     50        auto renderPass = commandQueue->createRenderPass(nullptr);
     51        renderPass->setRenderState(renderState);
     52        renderPass->setResources(0, { WebGPU::UniformBufferObjectReference(buffer.get()), WebGPU::TextureReference(texture.get()) });
     53        …
     54        renderPass->draw(3);
     55        commandQueue->commitRenderPass(std::move(renderPass));
     56        commandQueue->present();
     57       
     58        The first argument to the setResources() call identifies which set to populate with the supplied resources.
     59
     60        One tenant of the low-level graphics APIs is that, if you’ve enabled double buffering (or
     61        triple buffering), the GPU is executing one frame at the same time you are recording the
     62        next frame. This often means that you need duplicate resources so the CPU and GPU don’t step
     63        on each other’s toes. However, platforms have platform-specific requirements about whether
     64        or not they can be double / triple buffered, and we don’t want to expose this to the Web for
     65        fear of badly-authored programs.
     66
     67        To solve this, resources are reference counted, and the return type of getBuffer() is an
     68        RAII type called BufferHolder which increments and decrements the reference count
     69        automatically. The reference count is also incremented and decremented when the GPU is using
     70        the resource in a Pass. When the reference count reaches 0, the resource isn’t destroyed;
     71        instead, it’s simply moved to a “free list” which getBuffer() may pull from. Therefore,
     72        applications don’t need to know whether the frame buffer is double buffered or triple
     73        buffered; they can just getBuffer() each frame, and the correct number of buffers will be
     74        created and recycled.
     75       
     76        {
     77            auto buffer = device->getBuffer(bufferSize); // These get recycled
     78            … populate the buffer …
     79            auto renderPass = commandQueue->createRenderPass(nullptr);
     80            renderPass->setRenderState(renderState);
     81            renderPass->setResources(0, { WebGPU::UniformBufferObjectReference(buffer.get()) });
     82            …
     83            renderPass->draw(…);
     84            commandQueue->commitRenderPass(std::move(renderPass));
     85        }
     86        commandQueue->present();
     87
     88        In Direct3D and Vulkan, vertex buffers and index buffers are not part of the resource sets
     89        mentioned above. Instead, you tell the render state about the shape of the vertex and index
     90        buffers, and you swap them out independently in the draw loop. Metal and Vulkan have almost
     91        identical API to specify this shape of the vertex buffers, so I’ve mostly copied it. In this
     92        example, we have two vertex attributes, a vec2 and a vec3, which both come from the same
     93        buffer:
     94       
     95        // { Attribute format, offset within stride, buffer to pull from }
     96        std::vector<WebGPU::RenderState::VertexAttribute> vertexAttributes = { {WebGPU::RenderState::VertexFormat::Float2, 0, 0}, {WebGPU::RenderState::VertexFormat::Float3, sizeof(float) * 2, 0} };
     97        // A single vertex buffer, with a stride of 5 floats
     98        auto& renderState = device->getRenderState(vertexShader, "main", fragmentShader, "main", { sizeof(float) * 5 }, vertexAttributes, resourceTypes, nullptr);
     99       
     100        … later, in the draw() function …
     101       
     102        auto renderPass = commandQueue->createRenderPass(nullptr);
     103        renderPass->setRenderState(renderState);
     104        renderPass->setVertexAttributeBuffers({ vertexBuffer.get() }); // The one vertex buffer which both attributes pull from
     105        renderPass->setResources(…);
     106        …
     107        renderPass->draw(…);
     108        commandQueue->commitRenderPass(std::move(renderPass));
     109        commandQueue->present();
     110
     111        You can also tell the RenderState about how many render targets you have and their formats,
     112        and then when you create the RenderPass, you specify the specific textures you want to
     113        render into.
     114
     115        std::vector<WebGPU::PixelFormat> colorPixelFormats = { WebGPU::PixelFormat::RGBA8, WebGPU::PixelFormat::RGBA8 }; // Two render targets, with these formats
     116        auto& renderState = device->getRenderState(vertexShader, "main", fragmentShader, "main", vertexBufferStrides, vertexAttributes, resourceTypes, &colorPixelFormats);
     117       
     118        … later, in the draw() function …
     119       
     120        std::vector<std::reference_wrapper<WebGPU::Texture>> destinationTextures = { texture1->get(), texture2->get() };
     121        auto renderPass = commandQueue->createRenderPass(&destinationTextures);
     122        renderPass->setRenderState(renderState);
     123        …
     124        renderPass->draw(…);
     125        commandQueue->commitRenderPass(std::move(renderPass));
     126       
     127        // Now, draw one of the textures to the screen. Note that no synchronization is necessary here!
     128        auto renderPass = commandQueue->createRenderPass(nullptr);
     129        renderPass->setRenderState(renderState2);
     130        renderPass->setResources(0, { WebGPU:: TextureReference(texture1.get()) });
     131        …
     132        renderPass->draw(…);
     133        commandQueue->commitRenderPass(std::move(renderPass));
     134        commandQueue->present();
     135
     136        Just like how in Metal has Render Encoders and Compute Encoders, WebGPU has RenderPasses
     137        and ComputePasses.
     138
     139        auto& computeState = device->getComputeState(computeShader, "main", resourceTypes);
     140        …
     141        auto computePass = commandQueue->createComputePass();
     142        computePass->setComputeState(computeState);
     143        computePass->setResources(0, resources);
     144        computePass->dispatch(width, height, depth);
     145        commandQueue->commitComputePass(std::move(computePass));
     146       
     147        // Now, draw the resources we just computed. Note that no synchronization is necessary here!
     148        auto renderPass = commandQueue->createRenderPass(nullptr);
     149        renderPass->setRenderState(renderState);
     150        renderPass->setResources(0, resources });
     151        …
     152        renderPass->draw(…);
     153        commandQueue->commitRenderPass(std::move(renderPass));
     154        commandQueue->present();
     155
     156        There are also two other types of passes: one that corresponds to a Metal blit encoder, and
     157        one that allows the CPU to change the contents of GPU buffers and textures. This last kind
     158        of pass is a little interesting: you can’t just change the contents of a buffer at any time
     159        you feel like it, because that resource might be in use by the GPU. Therefore, we need to do
     160        the same kind of synchronization that we already do at render pass boundaries.
     161
     162        In addition, both Vulkan and Direct3D have a concept of a memory heap. A resource might
     163        exist inside a heap which is fast, but invisible from the CPU, or in a heap which is slow,
     164        but visible by the CPU. Certain operations are not possible from some types of images (e.g.
     165        non-tiled textures may not be able to be sampled from). The usual way to get around this
     166        problem is to have two resources: a slow staging resource which the CPU can see, and a fast
     167        resource which the CPU can’t see. Uploading data is a two-pass algorithm, where the CPU
     168        memcpy()s into the slow staging resource, and then a blit command is enqueued on the GPU to
     169        copy the contents of the staging resource to the real resource. This requires that the
     170        upload have access to the commandQueue so it can possibly enqueue a blit between the staging
     171        and real resources. Therefore, a pass is the right level of abstraction for these facilities.
     172
     173        std::queue<boost::unique_future<std::vector<uint8_t>>> futureQueue; // Promises for data downloads from the GPU
     174       
     175        … later, in the draw() function …
     176       
     177        // See if any of the previously-enqueued downloads are finished
     178        while (!futureQueue.empty() && futureQueue.front(). has_value()) {
     179            std::vector<uint8_t>& data = futureQueue.front().get();
     180            // Use the downloaded data
     181            futureQueue.pop();
     182        }
     183        …
     184        auto hostAccessPass = commandQueue->createHostAccessPass();
     185        hostAccessPass->overwriteBuffer(buffer->get(), bufferContents); // Upload data to a resource
     186       
     187        futureQueue.emplace(hostAccessPass->getBufferContents(buffer->get()));
     188        commandQueue->commitHostAccessPass(std::move(hostAccessPass));
     189       
     190        You can also issue copy commands between resources entirely on the GPU:
     191       
     192        auto blitPass = commandQueue->createBlitPass();
     193        blitPass->copyTexture(source->get(), destination->get(), sourceX, sourceY, destinationX, destinationY, width, height);
     194        commandQueue->commitBlitPass(std::move(blitPass));
     195
     196        * Scripts/webkitpy/style/checker.py:
     197        * WebGPUAPIStructure/Example/Example.cpp: Added.
     198        (readFile):
     199        (drawWebGPU):
     200        (wWinMain):
     201        (MyRegisterClass):
     202        (InitInstance):
     203        (WndProc):
     204        * WebGPUAPIStructure/Example/Example.h: Added.
     205        * WebGPUAPIStructure/Example/Example.ico: Added.
     206        * WebGPUAPIStructure/Example/Example.rc: Added.
     207        * WebGPUAPIStructure/Example/Example.vcxproj: Added.
     208        * WebGPUAPIStructure/Example/Example.vcxproj.filters: Added.
     209        * WebGPUAPIStructure/Example/Example.vcxproj.user: Added.
     210        * WebGPUAPIStructure/Example/resource.h: Added.
     211        * WebGPUAPIStructure/Example/small.ico: Added.
     212        * WebGPUAPIStructure/Example/stdafx.cpp: Added.
     213        * WebGPUAPIStructure/Example/stdafx.h: Added.
     214        * WebGPUAPIStructure/Example/targetver.h: Added.
     215        * WebGPUAPIStructure/WebGPU-Common/WebGPU-Common.vcxproj: Added.
     216        * WebGPUAPIStructure/WebGPU-Common/WebGPU-Common.vcxproj.filters: Added.
     217        * WebGPUAPIStructure/WebGPU-Common/WebGPU.cpp: Added.
     218        (WebGPU::BufferHolder::BufferHolder):
     219        (WebGPU::BufferHolder::~BufferHolder):
     220        (WebGPU::TextureHolder::TextureHolder):
     221        (WebGPU::TextureHolder::~TextureHolder):
     222        (WebGPU::SamplerHolder::SamplerHolder):
     223        (WebGPU::SamplerHolder::~SamplerHolder):
     224        * WebGPUAPIStructure/WebGPU-Common/WebGPU.h: Added.
     225        (WebGPU::Queue::~Queue):
     226        (WebGPU::RenderState::~RenderState):
     227        (WebGPU::ComputeState::~ComputeState):
     228        (WebGPU::Buffer::~Buffer):
     229        (WebGPU::Texture::~Texture):
     230        (WebGPU::Sampler::~Sampler):
     231        (WebGPU::TextureReference::TextureReference):
     232        (WebGPU::TextureReference::get const):
     233        (WebGPU::SamplerReference::SamplerReference):
     234        (WebGPU::SamplerReference::get const):
     235        (WebGPU::UniformBufferObjectReference::UniformBufferObjectReference):
     236        (WebGPU::UniformBufferObjectReference::get const):
     237        (WebGPU::ShaderStorageBufferObjectReference::ShaderStorageBufferObjectReference):
     238        (WebGPU::ShaderStorageBufferObjectReference::get const):
     239        (WebGPU::RenderPass::~RenderPass):
     240        (WebGPU::ComputePass::~ComputePass):
     241        (WebGPU::BlitPass::~BlitPass):
     242        (WebGPU::HostAccessPass::~HostAccessPass):
     243        (WebGPU::BufferHolder::get):
     244        (WebGPU::TextureHolder::get):
     245        (WebGPU::SamplerHolder::get):
     246        (WebGPU::Device::~Device):
     247        * WebGPUAPIStructure/WebGPU-Vulkan/BlitPassImpl.cpp: Added.
     248        (WebGPU::BlitPassImpl::BlitPassImpl):
     249        (WebGPU::BlitPassImpl::copyTexture):
     250        * WebGPUAPIStructure/WebGPU-Vulkan/BlitPassImpl.h: Added.
     251        * WebGPUAPIStructure/WebGPU-Vulkan/BufferImpl.cpp: Added.
     252        (WebGPU::BufferImpl::BufferImpl):
     253        (WebGPU::BufferImpl::decrementReferenceCount):
     254        * WebGPUAPIStructure/WebGPU-Vulkan/BufferImpl.h: Added.
     255        (WebGPU::BufferImpl::getBuffer const):
     256        (WebGPU::BufferImpl::getDeviceMemory const):
     257        (WebGPU::BufferImpl::incrementReferenceCount):
     258        (WebGPU::BufferImpl::getLength const):
     259        * WebGPUAPIStructure/WebGPU-Vulkan/ComputePassImpl.cpp: Added.
     260        (WebGPU::ComputePassImpl::ComputePassImpl):
     261        (WebGPU::ComputePassImpl::setComputeState):
     262        (WebGPU::ComputePassImpl::setResources):
     263        (WebGPU::ComputePassImpl::dispatch):
     264        * WebGPUAPIStructure/WebGPU-Vulkan/ComputePassImpl.h: Added.
     265        * WebGPUAPIStructure/WebGPU-Vulkan/ComputeStateImpl.cpp: Added.
     266        (WebGPU::ComputeStateImpl::ComputeStateImpl):
     267        * WebGPUAPIStructure/WebGPU-Vulkan/ComputeStateImpl.h: Added.
     268        (WebGPU::ComputeStateImpl::getPipeline const):
     269        (WebGPU::ComputeStateImpl::getPipelineLayout const):
     270        (WebGPU::ComputeStateImpl::getDescriptorSetLayouts const):
     271        * WebGPUAPIStructure/WebGPU-Vulkan/DeviceImpl.cpp: Added.
     272        (WebGPU::Device::create):
     273        (WebGPU::convertPixelFormat):
     274        (WebGPU::convertFormat):
     275        (WebGPU::debugReport):
     276        (WebGPU::DeviceImpl::DeviceImpl):
     277        (WebGPU::DeviceImpl::getCommandQueue):
     278        (WebGPU::DeviceImpl::prepareShader):
     279        (WebGPU::DeviceImpl::createPipelineLayout):
     280        (WebGPU::DeviceImpl::createCompatibleRenderPass):
     281        (WebGPU::convertVertexFormat):
     282        (WebGPU::DeviceImpl::getRenderState):
     283        (WebGPU::DeviceImpl::getComputeState):
     284        (WebGPU::DeviceImpl::getBuffer):
     285        (WebGPU::DeviceImpl::returnBuffer):
     286        (WebGPU::DeviceImpl::getTexture):
     287        (WebGPU::DeviceImpl::returnTexture):
     288        (WebGPU::DeviceImpl::getSampler):
     289        (WebGPU::DeviceImpl::returnSampler):
     290        (WebGPU::DeviceImpl::~DeviceImpl):
     291        * WebGPUAPIStructure/WebGPU-Vulkan/DeviceImpl.h: Added.
     292        (WebGPU::DeviceImpl::UniqueDebugReportCallbackEXT::UniqueDebugReportCallbackEXT):
     293        (WebGPU::DeviceImpl::UniqueDebugReportCallbackEXT::operator=):
     294        (WebGPU::DeviceImpl::UniqueDebugReportCallbackEXT::~UniqueDebugReportCallbackEXT):
     295        (WebGPU::DeviceImpl::UniqueDebugReportCallbackEXT::destroy):
     296        (WebGPU::DeviceImpl::TextureParameters::operator== const):
     297        (WebGPU::DeviceImpl::TextureParametersHash::operator() const):
     298        * WebGPUAPIStructure/WebGPU-Vulkan/HostAccessPassImpl.cpp: Added.
     299        (WebGPU::HostAccessPassImpl::HostAccessPassImpl):
     300        (WebGPU::HostAccessPassImpl::overwriteBuffer):
     301        (WebGPU::HostAccessPassImpl::getBufferContents):
     302        (WebGPU::HostAccessPassImpl::execute):
     303        * WebGPUAPIStructure/WebGPU-Vulkan/HostAccessPassImpl.h: Added.
     304        (WebGPU::HostAccessPassImpl::getFinishedEvent const):
     305        * WebGPUAPIStructure/WebGPU-Vulkan/PassImpl.cpp: Added.
     306        (WebGPU::PassImpl::PassImpl):
     307        (WebGPU::ResourceVisitor::operator()):
     308        (WebGPU::ResourceVisitor::getBindings const):
     309        (WebGPU::ResourceVisitor::releaseWriteDescriptorSets):
     310        (WebGPU::ResourceVisitor::getDescriptorImageInfos const):
     311        (WebGPU::ResourceVisitor::getDescriptorBufferInfos const):
     312        (WebGPU::ResourceVisitor::getBuffers const):
     313        (WebGPU::ResourceVisitor::getTextures const):
     314        (WebGPU::ResourceVisitor::getSamplers const):
     315        (WebGPU::ResourceVisitor::getImageCount const):
     316        (WebGPU::ResourceVisitor::getSamplerCount const):
     317        (WebGPU::ResourceVisitor::getUniformBufferCount const):
     318        (WebGPU::ResourceVisitor::getStorageBufferCount const):
     319        (WebGPU::PassImpl::setResources):
     320        (WebGPU::PassImpl::insertBuffer):
     321        (WebGPU::PassImpl::insertTexture):
     322        (WebGPU::PassImpl::insertSampler):
     323        * WebGPUAPIStructure/WebGPU-Vulkan/PassImpl.h: Added.
     324        (WebGPU::PassImpl::getCommandBuffer const):
     325        (WebGPU::PassImpl::iterateBuffers):
     326        (WebGPU::PassImpl::iterateTextures):
     327        (WebGPU::PassImpl::ResourceReference::ResourceReference):
     328        (WebGPU::PassImpl::ResourceReference::~ResourceReference):
     329        (WebGPU::PassImpl::ResourceReference::operator=):
     330        (WebGPU::PassImpl::ResourceReference::operator== const):
     331        (WebGPU::PassImpl::ResourceReference::get const):
     332        (WebGPU::PassImpl::ResourceReference::release):
     333        (WebGPU::PassImpl::ResourceReferenceHash::operator() const):
     334        * WebGPUAPIStructure/WebGPU-Vulkan/QueueImpl.cpp: Added.
     335        (WebGPU::QueueImpl::QueueImpl):
     336        (WebGPU::QueueImpl::prepareCurrentFrame):
     337        (WebGPU::QueueImpl::createSpecificRenderPass):
     338        (WebGPU::QueueImpl::createFramebuffer):
     339        (WebGPU::QueueImpl::createRenderPass):
     340        (WebGPU::QueueImpl::commitRenderPass):
     341        (WebGPU::QueueImpl::createComputePass):
     342        (WebGPU::QueueImpl::commitComputePass):
     343        (WebGPU::QueueImpl::createBlitPass):
     344        (WebGPU::QueueImpl::commitBlitPass):
     345        (WebGPU::QueueImpl::createHostAccessPass):
     346        (WebGPU::QueueImpl::commitHostAccessPass):
     347        (WebGPU::QueueImpl::present):
     348        (WebGPU::QueueImpl::commitPass):
     349        (WebGPU::QueueImpl::synchronizeResources):
     350        (WebGPU::QueueImpl::~QueueImpl):
     351        * WebGPUAPIStructure/WebGPU-Vulkan/QueueImpl.h: Added.
     352        * WebGPUAPIStructure/WebGPU-Vulkan/RenderPassImpl.cpp: Added.
     353        (WebGPU::RenderPassImpl::RenderPassImpl):
     354        (WebGPU::RenderPassImpl::setRenderState):
     355        (WebGPU::RenderPassImpl::setVertexAttributeBuffers):
     356        (WebGPU::RenderPassImpl::setResources):
     357        (WebGPU::RenderPassImpl::setViewport):
     358        (WebGPU::RenderPassImpl::setScissorRect):
     359        (WebGPU::RenderPassImpl::draw):
     360        * WebGPUAPIStructure/WebGPU-Vulkan/RenderPassImpl.h: Added.
     361        * WebGPUAPIStructure/WebGPU-Vulkan/RenderStateImpl.cpp: Added.
     362        (WebGPU::RenderStateImpl::RenderStateImpl):
     363        * WebGPUAPIStructure/WebGPU-Vulkan/RenderStateImpl.h: Added.
     364        (WebGPU::RenderStateImpl::getPipeline const):
     365        (WebGPU::RenderStateImpl::getPipelineLayout const):
     366        (WebGPU::RenderStateImpl::getDescriptorSetLayouts const):
     367        * WebGPUAPIStructure/WebGPU-Vulkan/SamplerImpl.cpp: Added.
     368        (WebGPU::SamplerImpl::SamplerImpl):
     369        (WebGPU::SamplerImpl::decrementReferenceCount):
     370        * WebGPUAPIStructure/WebGPU-Vulkan/SamplerImpl.h: Added.
     371        (WebGPU::SamplerImpl::getSampler):
     372        (WebGPU::SamplerImpl::incrementReferenceCount):
     373        (WebGPU::SamplerImpl::getFilter):
     374        (WebGPU::SamplerImpl::getMipmapMode):
     375        (WebGPU::SamplerImpl::getAddressMode):
     376        * WebGPUAPIStructure/WebGPU-Vulkan/TextureImpl.cpp: Added.
     377        (WebGPU::TextureImpl::TextureImpl):
     378        (WebGPU::TextureImpl::decrementReferenceCount):
     379        * WebGPUAPIStructure/WebGPU-Vulkan/TextureImpl.h: Added.
     380        (WebGPU::TextureImpl::getImage const):
     381        (WebGPU::TextureImpl::getImageView const):
     382        (WebGPU::TextureImpl::getFormat const):
     383        (WebGPU::TextureImpl::incrementReferenceCount):
     384        (WebGPU::TextureImpl::getWidth const):
     385        (WebGPU::TextureImpl::getHeight const):
     386        (WebGPU::TextureImpl::getTransferredToGPU const):
     387        (WebGPU::TextureImpl::setTransferredToGPU):
     388        * WebGPUAPIStructure/WebGPU-Vulkan/WebGPU-Vulkan.vcxproj: Added.
     389        * WebGPUAPIStructure/WebGPU-Vulkan/WebGPU-Vulkan.vcxproj.filters: Added.
     390        * WebGPUAPIStructure/WebGPU.sln: Added.
     391
    13922017-10-26  Eric Carlson  <eric.carlson@apple.com>
    2393
  • trunk/Tools/Scripts/webkitpy/style/checker.py

    r224014 r224065  
    214214    ([os.path.join('webkitpy', 'thirdparty'),
    215215      os.path.join('Source', 'ThirdParty', 'ANGLE'),
    216       os.path.join('Source', 'ThirdParty', 'xdgmime')],
     216      os.path.join('Source', 'ThirdParty', 'xdgmime'),
     217      os.path.join('Tools', 'WebGPUAPIStructure')],
    217218     ["-",
    218219      "+pep8/W191",  # Tabs
Note: See TracChangeset for help on using the changeset viewer.