<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[244147] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/244147">244147</a></dd>
<dt>Author</dt> <dd>justin_fan@apple.com</dd>
<dt>Date</dt> <dd>2019-04-10 13:48:38 -0700 (Wed, 10 Apr 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>[Web GPU] Indexed drawing and GPUCommandEncoder crash prevention
https://bugs.webkit.org/show_bug.cgi?id=196758

Reviewed by Dean Jackson.

Source/WebCore:

Test: webgpu/draw-indexed-triangles.html

Implement GPURenderPassEncoder::setIndexBuffer and GPURenderPassEncoder::drawIndexed to enable indexed drawing.
Disable GPUCommandEncoders with active pass encoders from being submitted or encoding blits.

Prevent active GPUCommandEncoders from being submitted or encoding blit commands:
* Modules/webgpu/WebGPUCommandEncoder.cpp:
(WebCore::WebGPUCommandEncoder::finish):
* platform/graphics/gpu/cocoa/GPUCommandBufferMetal.mm:
(WebCore::GPUCommandBuffer::copyBufferToBuffer):
(WebCore::GPUCommandBuffer::copyBufferToTexture):
(WebCore::GPUCommandBuffer::copyTextureToBuffer):
(WebCore::GPUCommandBuffer::copyTextureToTexture):

Implement GPURenderPassEncoder::setIndexBuffer and GPURenderPassEncoder::drawIndexed:
* Modules/webgpu/WebGPURenderPassEncoder.cpp:
(WebCore::WebGPURenderPassEncoder::setIndexBuffer):
(WebCore::WebGPURenderPassEncoder::setVertexBuffers): Remove unnecessary move operations.
(WebCore::WebGPURenderPassEncoder::drawIndexed): Added.
* Modules/webgpu/WebGPURenderPassEncoder.h:
* Modules/webgpu/WebGPURenderPassEncoder.idl:
* platform/graphics/gpu/GPUBuffer.h:
(WebCore::GPUBuffer::isIndex const):
* platform/graphics/gpu/GPUInputStateDescriptor.h:
* platform/graphics/gpu/GPURenderPassEncoder.h: Cache the index buffer, as Metal does not set the index buffer separate from the draw call.
* platform/graphics/gpu/GPURenderPipeline.h:
(WebCore::GPURenderPipeline::indexFormat const):
* platform/graphics/gpu/cocoa/GPURenderPassEncoderMetal.mm:
(WebCore::GPURenderPassEncoder::setIndexBuffer):
(WebCore::GPURenderPassEncoder::setVertexBuffers):
(WebCore::mtlPrimitiveTypeForGPUPrimitiveTopology):
(WebCore::GPURenderPassEncoder::draw):
(WebCore::mtlIndexTypeForGPUIndexFormat): Added.
(WebCore::GPURenderPassEncoder::drawIndexed): Added.
(WebCore::primitiveTypeForGPUPrimitiveTopology): Deleted.
* platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm:
(WebCore::GPURenderPipeline::tryCreate):
(WebCore::GPURenderPipeline::GPURenderPipeline):

LayoutTests:

Add draw-indexed-triangles to test drawing a green square using GPURenderPassEncoder::setIndexBuffer and drawIndexed.

* webgpu/draw-indexed-triangles-expected.html: Added.
* webgpu/draw-indexed-triangles.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModuleswebgpuWebGPUCommandEncodercpp">trunk/Source/WebCore/Modules/webgpu/WebGPUCommandEncoder.cpp</a></li>
<li><a href="#trunkSourceWebCoreModuleswebgpuWebGPURenderPassEncodercpp">trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp</a></li>
<li><a href="#trunkSourceWebCoreModuleswebgpuWebGPURenderPassEncoderh">trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.h</a></li>
<li><a href="#trunkSourceWebCoreModuleswebgpuWebGPURenderPassEncoderidl">trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.idl</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsgpuGPUBufferh">trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsgpuGPUInputStateDescriptorh">trunk/Source/WebCore/platform/graphics/gpu/GPUInputStateDescriptor.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsgpuGPURenderPassEncoderh">trunk/Source/WebCore/platform/graphics/gpu/GPURenderPassEncoder.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsgpuGPURenderPipelineh">trunk/Source/WebCore/platform/graphics/gpu/GPURenderPipeline.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsgpucocoaGPUCommandBufferMetalmm">trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUCommandBufferMetal.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsgpucocoaGPURenderPassEncoderMetalmm">trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPassEncoderMetal.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsgpucocoaGPURenderPipelineMetalmm">trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestswebgpudrawindexedtrianglesexpectedhtml">trunk/LayoutTests/webgpu/draw-indexed-triangles-expected.html</a></li>
<li><a href="#trunkLayoutTestswebgpudrawindexedtriangleshtml">trunk/LayoutTests/webgpu/draw-indexed-triangles.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (244146 => 244147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2019-04-10 20:44:34 UTC (rev 244146)
+++ trunk/LayoutTests/ChangeLog 2019-04-10 20:48:38 UTC (rev 244147)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2019-04-10  Justin Fan  <justin_fan@apple.com>
+
+        [Web GPU] Indexed drawing and GPUCommandEncoder crash prevention
+        https://bugs.webkit.org/show_bug.cgi?id=196758
+
+        Reviewed by Dean Jackson.
+
+        Add draw-indexed-triangles to test drawing a green square using GPURenderPassEncoder::setIndexBuffer and drawIndexed.
+
+        * webgpu/draw-indexed-triangles-expected.html: Added.
+        * webgpu/draw-indexed-triangles.html: Added.
+
</ins><span class="cx"> 2019-04-10  Megan Gardner  <megan_gardner@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Fix text autoscrolling when typing in modern webkit
</span></span></pre></div>
<a id="trunkLayoutTestswebgpudrawindexedtrianglesexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/webgpu/draw-indexed-triangles-expected.html (0 => 244147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/webgpu/draw-indexed-triangles-expected.html                            (rev 0)
+++ trunk/LayoutTests/webgpu/draw-indexed-triangles-expected.html       2019-04-10 20:48:38 UTC (rev 244147)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Reference File</title>
+<p>Pass if square canvas below is completely green.</p>
+<canvas width="400" height="400"></canvas>
+<script>
+const canvas = document.querySelector("canvas");
+const context = canvas.getContext('2d');
+
+context.fillStyle = 'rgb(0, 255, 0)';
+context.fillRect(0, 0, canvas.width, canvas.height);
+</script>
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkLayoutTestswebgpudrawindexedtriangleshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/webgpu/draw-indexed-triangles.html (0 => 244147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/webgpu/draw-indexed-triangles.html                             (rev 0)
+++ trunk/LayoutTests/webgpu/draw-indexed-triangles.html        2019-04-10 20:48:38 UTC (rev 244147)
</span><span class="lines">@@ -0,0 +1,122 @@
</span><ins>+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebGPU Hello Triangles</title>
+<meta name="assert" content="WebGPU correctly renders a green canvas.">
+<link rel="match" href="draw-indexed-triangles-expected.html">
+<p>Pass if square canvas below is completely green.</p>
+<canvas width="400" height="400"></canvas>
+<script src="js/webgpu-functions.js"></script>
+<script>
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+const shaderCode = `
+#include <metal_stdlib>
+    
+using namespace metal;
+
+struct VertexIn
+{
+    float4 position [[attribute(0)]];
+    float green [[attribute(1)]];
+};
+
+struct VertexOut
+{
+    float4 position [[position]];
+    float4 color;
+};
+
+vertex VertexOut vertex_main(VertexIn vertexIn [[stage_in]])
+{
+    VertexOut vOut;
+    vOut.position = vertexIn.position;
+    vOut.color = float4(0, vertexIn.green, 0, 1);
+    return vOut;
+}
+
+fragment float4 fragment_main(VertexOut v [[stage_in]])
+{
+    return v.color;
+}
+`
+
+function createVertexBuffer(device) {
+    const vertexArray = new Float32Array([
+        // float4 xyzw, float g
+        -1, 1, 0, 1, 0,
+        -1, 1, 0, 1, 1,
+        -1, -1, 0, 1, 0,
+        -1, -1, 0, 1, 1,
+        1, 1, 0, 1, 0,
+        1, 1, 0, 1, 1,
+        1, -1, 0, 1, 0,
+        1, -1, 0, 1, 1
+    ]);
+    const buffer = device.createBuffer({ size: vertexArray.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST });
+    buffer.setSubData(0, vertexArray.buffer);
+
+    return buffer;
+}
+
+const indexBufferOffset = 2048; // Test a buffer offset for index array.
+const indexOffset = -9001; // Test a base index to add to index array values.
+
+function createIndexBuffer(device) {
+    const offsetArray = [1, 3, 5, 3, 5, 7].map(v => { return v - indexOffset; });
+    const indexArray = new Uint32Array([1, 3, 5, 3, 5, 7].map(v => { return v - indexOffset; }));
+    const buffer = device.createBuffer({ size: indexArray.byteLength + indexBufferOffset, usage: GPUBufferUsage.INDEX | GPUBufferUsage.TRANSFER_DST });
+    buffer.setSubData(indexBufferOffset, indexArray.buffer);
+
+    return buffer;
+}
+
+function createInputStateDescriptor() {
+    return {
+        indexFormat: "uint32",
+        attributes: [{
+            shaderLocation: 0,
+            inputSlot: 0,
+            offset: 0,
+            format: "float4"
+        }, {
+            shaderLocation: 1,
+            inputSlot: 0,
+            offset: 4 * 4,
+            format: "float"
+        }],
+        inputs: [{
+            inputSlot: 0,
+            stride: 4 * 5,
+            stepMode: "vertex"
+        }]
+    };
+}
+
+async function test() {
+    const device = await getBasicDevice();
+    const canvas = document.querySelector("canvas");
+    const swapChain = createBasicSwapChain(canvas, device);
+    // FIXME: Replace with non-MSL shaders.
+    const shaderModule = device.createShaderModule({ code: shaderCode });
+    const vertexBuffer = createVertexBuffer(device);
+    const indexBuffer = createIndexBuffer(device);
+    const pipeline = createBasicPipeline(shaderModule, device, null, null, createInputStateDescriptor(), null, "triangle-list");
+    const commandEncoder = device.createCommandEncoder();
+    const passEncoder = beginBasicRenderPass(swapChain, commandEncoder);
+
+    passEncoder.setIndexBuffer(indexBuffer, indexBufferOffset);
+    passEncoder.setVertexBuffers(0, [vertexBuffer], [0]);
+    passEncoder.setPipeline(pipeline);
+    passEncoder.drawIndexed(6, 1, 0, indexOffset, 0);
+    passEncoder.endPass();
+
+    device.getQueue().submit([commandEncoder.finish()]);
+    vertexBuffer.destroy();
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+test();
+</script>
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (244146 => 244147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2019-04-10 20:44:34 UTC (rev 244146)
+++ trunk/Source/WebCore/ChangeLog      2019-04-10 20:48:38 UTC (rev 244147)
</span><span class="lines">@@ -1,3 +1,49 @@
</span><ins>+2019-04-10  Justin Fan  <justin_fan@apple.com>
+
+        [Web GPU] Indexed drawing and GPUCommandEncoder crash prevention
+        https://bugs.webkit.org/show_bug.cgi?id=196758
+
+        Reviewed by Dean Jackson.
+
+        Test: webgpu/draw-indexed-triangles.html
+
+        Implement GPURenderPassEncoder::setIndexBuffer and GPURenderPassEncoder::drawIndexed to enable indexed drawing.
+        Disable GPUCommandEncoders with active pass encoders from being submitted or encoding blits. 
+
+        Prevent active GPUCommandEncoders from being submitted or encoding blit commands:
+        * Modules/webgpu/WebGPUCommandEncoder.cpp:
+        (WebCore::WebGPUCommandEncoder::finish):
+        * platform/graphics/gpu/cocoa/GPUCommandBufferMetal.mm:
+        (WebCore::GPUCommandBuffer::copyBufferToBuffer):
+        (WebCore::GPUCommandBuffer::copyBufferToTexture):
+        (WebCore::GPUCommandBuffer::copyTextureToBuffer):
+        (WebCore::GPUCommandBuffer::copyTextureToTexture):
+
+        Implement GPURenderPassEncoder::setIndexBuffer and GPURenderPassEncoder::drawIndexed:
+        * Modules/webgpu/WebGPURenderPassEncoder.cpp:
+        (WebCore::WebGPURenderPassEncoder::setIndexBuffer):
+        (WebCore::WebGPURenderPassEncoder::setVertexBuffers): Remove unnecessary move operations.
+        (WebCore::WebGPURenderPassEncoder::drawIndexed): Added.
+        * Modules/webgpu/WebGPURenderPassEncoder.h:
+        * Modules/webgpu/WebGPURenderPassEncoder.idl:
+        * platform/graphics/gpu/GPUBuffer.h:
+        (WebCore::GPUBuffer::isIndex const):
+        * platform/graphics/gpu/GPUInputStateDescriptor.h:
+        * platform/graphics/gpu/GPURenderPassEncoder.h: Cache the index buffer, as Metal does not set the index buffer separate from the draw call.
+        * platform/graphics/gpu/GPURenderPipeline.h:
+        (WebCore::GPURenderPipeline::indexFormat const):
+        * platform/graphics/gpu/cocoa/GPURenderPassEncoderMetal.mm:
+        (WebCore::GPURenderPassEncoder::setIndexBuffer):
+        (WebCore::GPURenderPassEncoder::setVertexBuffers):
+        (WebCore::mtlPrimitiveTypeForGPUPrimitiveTopology):
+        (WebCore::GPURenderPassEncoder::draw):
+        (WebCore::mtlIndexTypeForGPUIndexFormat): Added.
+        (WebCore::GPURenderPassEncoder::drawIndexed): Added.
+        (WebCore::primitiveTypeForGPUPrimitiveTopology): Deleted.
+        * platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm:
+        (WebCore::GPURenderPipeline::tryCreate):
+        (WebCore::GPURenderPipeline::GPURenderPipeline):
+
</ins><span class="cx"> 2019-04-09  Ryosuke Niwa  <rniwa@webkit.org>
</span><span class="cx"> 
</span><span class="cx">         OfflineAudioDestinationNode::startRendering leaks OfflineAudioDestinationNode if offlineRender exists early
</span></span></pre></div>
<a id="trunkSourceWebCoreModuleswebgpuWebGPUCommandEncodercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUCommandEncoder.cpp (244146 => 244147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/webgpu/WebGPUCommandEncoder.cpp     2019-04-10 20:44:34 UTC (rev 244146)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPUCommandEncoder.cpp        2019-04-10 20:48:38 UTC (rev 244147)
</span><span class="lines">@@ -167,7 +167,7 @@
</span><span class="cx">     
</span><span class="cx"> Ref<WebGPUCommandBuffer> WebGPUCommandEncoder::finish()
</span><span class="cx"> {
</span><del>-    if (!m_commandBuffer) {
</del><ins>+    if (!m_commandBuffer || m_commandBuffer->isEncodingPass()) {
</ins><span class="cx">         LOG(WebGPU, "WebGPUCommandEncoder::finish(): Invalid operation!");
</span><span class="cx">         return WebGPUCommandBuffer::create(nullptr);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebCoreModuleswebgpuWebGPURenderPassEncodercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp (244146 => 244147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp  2019-04-10 20:44:34 UTC (rev 244146)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp     2019-04-10 20:48:38 UTC (rev 244147)
</span><span class="lines">@@ -92,8 +92,22 @@
</span><span class="cx">     m_passEncoder->setScissorRect(x, y, width, height);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebGPURenderPassEncoder::setVertexBuffers(unsigned startSlot, Vector<RefPtr<WebGPUBuffer>>&& buffers, Vector<uint64_t>&& offsets)
</del><ins>+void WebGPURenderPassEncoder::setIndexBuffer(WebGPUBuffer& buffer, uint64_t offset)
</ins><span class="cx"> {
</span><ins>+    if (!m_passEncoder) {
+        LOG(WebGPU, "GPURenderPassEncoder::setIndexBuffer(): Invalid operation!");
+        return;
+    }
+    if (!buffer.buffer() || !buffer.buffer()->isIndex()) {
+        LOG(WebGPU, "GPURenderPassEncoder::setIndexBuffer(): Invalid GPUBuffer!");
+        return;
+    }
+
+    m_passEncoder->setIndexBuffer(*buffer.buffer(), offset);
+}
+
+void WebGPURenderPassEncoder::setVertexBuffers(unsigned startSlot, const Vector<RefPtr<WebGPUBuffer>>& buffers, const Vector<uint64_t>& offsets)
+{
</ins><span class="cx"> #if !LOG_DISABLED
</span><span class="cx">     const char* const functionName = "GPURenderPassEncoder::setVertexBuffers()";
</span><span class="cx"> #endif
</span><span class="lines">@@ -113,7 +127,7 @@
</span><span class="cx">     Vector<Ref<GPUBuffer>> gpuBuffers;
</span><span class="cx">     gpuBuffers.reserveCapacity(buffers.size());
</span><span class="cx"> 
</span><del>-    for (const auto& buffer : buffers) {
</del><ins>+    for (auto& buffer : buffers) {
</ins><span class="cx">         if (!buffer || !buffer->buffer()) {
</span><span class="cx">             LOG(WebGPU, "%s: Invalid or destroyed buffer in list!", functionName);
</span><span class="cx">             return;
</span><span class="lines">@@ -127,7 +141,7 @@
</span><span class="cx">         gpuBuffers.uncheckedAppend(makeRef(*buffer->buffer()));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    m_passEncoder->setVertexBuffers(startSlot, WTFMove(gpuBuffers), WTFMove(offsets));
</del><ins>+    m_passEncoder->setVertexBuffers(startSlot, gpuBuffers, offsets);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebGPURenderPassEncoder::draw(unsigned vertexCount, unsigned instanceCount, unsigned firstVertex, unsigned firstInstance)
</span><span class="lines">@@ -140,6 +154,16 @@
</span><span class="cx">     m_passEncoder->draw(vertexCount, instanceCount, firstVertex, firstInstance);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebGPURenderPassEncoder::drawIndexed(unsigned indexCount, unsigned instanceCount, unsigned firstIndex, int baseVertex, unsigned firstInstance)
+{
+    if (!m_passEncoder) {
+        LOG(WebGPU, "GPURenderPassEncoder::draw(): Invalid operation!");
+        return;
+    }
+    // FIXME: Add Web GPU validation.
+    m_passEncoder->drawIndexed(indexCount, instanceCount, firstIndex, baseVertex, firstInstance);
+}
+
</ins><span class="cx"> GPUProgrammablePassEncoder* WebGPURenderPassEncoder::passEncoder()
</span><span class="cx"> {
</span><span class="cx">     return m_passEncoder.get();
</span></span></pre></div>
<a id="trunkSourceWebCoreModuleswebgpuWebGPURenderPassEncoderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.h (244146 => 244147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.h    2019-04-10 20:44:34 UTC (rev 244146)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.h       2019-04-10 20:48:38 UTC (rev 244147)
</span><span class="lines">@@ -48,8 +48,10 @@
</span><span class="cx">     void setBlendColor(const GPUColor&);
</span><span class="cx">     void setViewport(float x, float y, float width, float height, float minDepth, float maxDepth);
</span><span class="cx">     void setScissorRect(unsigned x, unsigned y, unsigned width, unsigned height);
</span><del>-    void setVertexBuffers(unsigned, Vector<RefPtr<WebGPUBuffer>>&&, Vector<uint64_t>&&);
</del><ins>+    void setIndexBuffer(WebGPUBuffer&, uint64_t offset);
+    void setVertexBuffers(unsigned startSlot, const Vector<RefPtr<WebGPUBuffer>>&, const Vector<uint64_t>& offsets);
</ins><span class="cx">     void draw(unsigned vertexCount, unsigned instanceCount, unsigned firstVertex, unsigned firstInstance);
</span><ins>+    void drawIndexed(unsigned indexCount, unsigned instanceCount, unsigned firstIndex, int baseVertex, unsigned firstInstance);
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     WebGPURenderPassEncoder(RefPtr<GPURenderPassEncoder>&&);
</span></span></pre></div>
<a id="trunkSourceWebCoreModuleswebgpuWebGPURenderPassEncoderidl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.idl (244146 => 244147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.idl  2019-04-10 20:44:34 UTC (rev 244146)
+++ trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.idl     2019-04-10 20:48:38 UTC (rev 244147)
</span><span class="lines">@@ -24,6 +24,7 @@
</span><span class="cx">  */
</span><span class="cx"> // https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
</span><span class="cx"> 
</span><ins>+typedef long i32;
</ins><span class="cx"> typedef unsigned long u32;
</span><span class="cx"> typedef unsigned long long u64;
</span><span class="cx"> 
</span><span class="lines">@@ -42,15 +43,13 @@
</span><span class="cx">     // Width and height must be greater than 0. Otherwise, an error will be generated.
</span><span class="cx">     void setScissorRect(u32 x, u32 y, u32 width, u32 height);
</span><span class="cx"> 
</span><ins>+    void setIndexBuffer(WebGPUBuffer buffer, u64 offset);
</ins><span class="cx">     void setVertexBuffers(u32 startSlot, sequence<WebGPUBuffer> buffers, sequence<u64> offsets);
</span><span class="cx"> 
</span><span class="cx">     void draw(u32 vertexCount, u32 instanceCount, u32 firstVertex, u32 firstInstance);
</span><ins>+    void drawIndexed(u32 indexCount, u32 instanceCount, u32 firstIndex, i32 baseVertex, u32 firstInstance);
</ins><span class="cx"> 
</span><span class="cx"> /* Not Yet Implemented
</span><del>-    void setIndexBuffer(WebGPUBuffer buffer, u64 offset);
-
-    void drawIndexed(u32 indexCount, u32 instanceCount, u32 firstIndex, i32 baseVertex, u32 firstInstance);
-
-    // TODO add missing commands
</del><ins>+    void setStencilReference(u32 reference);
</ins><span class="cx"> */
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsgpuGPUBufferh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.h (244146 => 244147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.h   2019-04-10 20:44:34 UTC (rev 244146)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.h      2019-04-10 20:48:38 UTC (rev 244147)
</span><span class="lines">@@ -74,6 +74,7 @@
</span><span class="cx">     uint64_t byteLength() const { return m_byteLength; }
</span><span class="cx">     bool isTransferSource() const { return m_usage.contains(GPUBufferUsage::Flags::TransferSource); }
</span><span class="cx">     bool isTransferDestination() const { return m_usage.contains(GPUBufferUsage::Flags::TransferDestination); }
</span><ins>+    bool isIndex() const { return m_usage.contains(GPUBufferUsage::Flags::Index); }
</ins><span class="cx">     bool isVertex() const { return m_usage.contains(GPUBufferUsage::Flags::Vertex); }
</span><span class="cx">     bool isUniform() const { return m_usage.contains(GPUBufferUsage::Flags::Uniform); }
</span><span class="cx">     bool isStorage() const { return m_usage.contains(GPUBufferUsage::Flags::Storage); }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsgpuGPUInputStateDescriptorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/gpu/GPUInputStateDescriptor.h (244146 => 244147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/gpu/GPUInputStateDescriptor.h     2019-04-10 20:44:34 UTC (rev 244146)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPUInputStateDescriptor.h        2019-04-10 20:48:38 UTC (rev 244147)
</span><span class="lines">@@ -39,7 +39,7 @@
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> struct GPUInputStateDescriptor {
</span><del>-    GPUIndexFormat indexFormat;
</del><ins>+    Optional<GPUIndexFormat> indexFormat;
</ins><span class="cx"> 
</span><span class="cx">     Vector<GPUVertexAttributeDescriptor> attributes;
</span><span class="cx">     Vector<GPUVertexInputDescriptor> inputs;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsgpuGPURenderPassEncoderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/gpu/GPURenderPassEncoder.h (244146 => 244147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/gpu/GPURenderPassEncoder.h        2019-04-10 20:44:34 UTC (rev 244146)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPURenderPassEncoder.h   2019-04-10 20:48:38 UTC (rev 244147)
</span><span class="lines">@@ -56,8 +56,10 @@
</span><span class="cx">     void setBlendColor(const GPUColor&);
</span><span class="cx">     void setViewport(float x, float y, float width, float height, float minDepth, float maxDepth);
</span><span class="cx">     void setScissorRect(unsigned x, unsigned y, unsigned width, unsigned height);
</span><del>-    void setVertexBuffers(unsigned, Vector<Ref<GPUBuffer>>&&, Vector<uint64_t>&&);
</del><ins>+    void setIndexBuffer(GPUBuffer&, uint64_t offset);
+    void setVertexBuffers(unsigned index, const Vector<Ref<GPUBuffer>>&, const Vector<uint64_t>& offsets);
</ins><span class="cx">     void draw(unsigned vertexCount, unsigned instanceCount, unsigned firstVertex, unsigned firstInstance);
</span><ins>+    void drawIndexed(unsigned indexCount, unsigned instanceCount, unsigned firstIndex, int baseVertex, unsigned firstInstance);
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     GPURenderPassEncoder(Ref<GPUCommandBuffer>&&, PlatformRenderPassEncoderSmartPtr&&);
</span><span class="lines">@@ -70,6 +72,9 @@
</span><span class="cx">     void useResource(const MTLResource *, unsigned usage) final;
</span><span class="cx">     void setVertexBuffer(const MTLBuffer *, unsigned offset, unsigned index) final;
</span><span class="cx">     void setFragmentBuffer(const MTLBuffer *, unsigned offset, unsigned index) final;
</span><ins>+
+    RefPtr<GPUBuffer> m_indexBuffer;
+    uint64_t m_indexBufferOffset;
</ins><span class="cx"> #endif // USE(METAL)
</span><span class="cx"> 
</span><span class="cx">     PlatformRenderPassEncoderSmartPtr m_platformRenderPassEncoder;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsgpuGPURenderPipelineh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/gpu/GPURenderPipeline.h (244146 => 244147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/gpu/GPURenderPipeline.h   2019-04-10 20:44:34 UTC (rev 244146)
+++ trunk/Source/WebCore/platform/graphics/gpu/GPURenderPipeline.h      2019-04-10 20:48:38 UTC (rev 244147)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> #if ENABLE(WEBGPU)
</span><span class="cx"> 
</span><span class="cx"> #include "GPURenderPipelineDescriptor.h"
</span><ins>+#include <wtf/Optional.h>
</ins><span class="cx"> #include <wtf/RefCounted.h>
</span><span class="cx"> #include <wtf/RefPtr.h>
</span><span class="cx"> #include <wtf/RetainPtr.h>
</span><span class="lines">@@ -53,15 +54,17 @@
</span><span class="cx"> #endif
</span><span class="cx">     PlatformRenderPipeline* platformRenderPipeline() const { return m_platformRenderPipeline.get(); }
</span><span class="cx">     GPUPrimitiveTopology primitiveTopology() const { return m_primitiveTopology; }
</span><ins>+    Optional<GPUIndexFormat> indexFormat() const { return m_indexFormat; }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx"> #if USE(METAL)
</span><del>-    GPURenderPipeline(RetainPtr<MTLDepthStencilState>&&, PlatformRenderPipelineSmartPtr&&, GPUPrimitiveTopology);
</del><ins>+    GPURenderPipeline(RetainPtr<MTLDepthStencilState>&&, PlatformRenderPipelineSmartPtr&&, GPUPrimitiveTopology, Optional<GPUIndexFormat>);
</ins><span class="cx"> 
</span><span class="cx">     RetainPtr<MTLDepthStencilState> m_depthStencilState;
</span><span class="cx"> #endif // USE(METAL)
</span><span class="cx">     PlatformRenderPipelineSmartPtr m_platformRenderPipeline;
</span><span class="cx">     GPUPrimitiveTopology m_primitiveTopology;
</span><ins>+    Optional<GPUIndexFormat> m_indexFormat;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsgpucocoaGPUCommandBufferMetalmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUCommandBufferMetal.mm (244146 => 244147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUCommandBufferMetal.mm        2019-04-10 20:44:34 UTC (rev 244146)
+++ trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUCommandBufferMetal.mm   2019-04-10 20:48:38 UTC (rev 244147)
</span><span class="lines">@@ -95,7 +95,7 @@
</span><span class="cx"> 
</span><span class="cx"> void GPUCommandBuffer::copyBufferToBuffer(Ref<GPUBuffer>&& src, uint64_t srcOffset, Ref<GPUBuffer>&& dst, uint64_t dstOffset, uint64_t size)
</span><span class="cx"> {
</span><del>-    if (!src->isTransferSource() || !dst->isTransferDestination()) {
</del><ins>+    if (isEncodingPass() || !src->isTransferSource() || !dst->isTransferDestination()) {
</ins><span class="cx">         LOG(WebGPU, "GPUCommandBuffer::copyBufferToBuffer(): Invalid operation!");
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="lines">@@ -132,7 +132,7 @@
</span><span class="cx"> 
</span><span class="cx"> void GPUCommandBuffer::copyBufferToTexture(GPUBufferCopyView&& srcBuffer, GPUTextureCopyView&& dstTexture, const GPUExtent3D& size)
</span><span class="cx"> {
</span><del>-    if (!srcBuffer.buffer->isTransferSource() || !dstTexture.texture->isTransferDestination()) {
</del><ins>+    if (isEncodingPass() || !srcBuffer.buffer->isTransferSource() || !dstTexture.texture->isTransferDestination()) {
</ins><span class="cx">         LOG(WebGPU, "GPUComandBuffer::copyBufferToTexture(): Invalid operation!");
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="lines">@@ -170,7 +170,7 @@
</span><span class="cx"> 
</span><span class="cx"> void GPUCommandBuffer::copyTextureToBuffer(GPUTextureCopyView&& srcTexture, GPUBufferCopyView&& dstBuffer, const GPUExtent3D& size)
</span><span class="cx"> {
</span><del>-    if (!srcTexture.texture->isTransferSource() || !dstBuffer.buffer->isTransferDestination()) {
</del><ins>+    if (isEncodingPass() || !srcTexture.texture->isTransferSource() || !dstBuffer.buffer->isTransferDestination()) {
</ins><span class="cx">         LOG(WebGPU, "GPUCommandBuffer::copyTextureToBuffer(): Invalid operation!");
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="lines">@@ -198,7 +198,7 @@
</span><span class="cx"> 
</span><span class="cx"> void GPUCommandBuffer::copyTextureToTexture(GPUTextureCopyView&& src, GPUTextureCopyView&& dst, const GPUExtent3D& size)
</span><span class="cx"> {
</span><del>-    if (!src.texture->isTransferSource() || !dst.texture->isTransferDestination()) {
</del><ins>+    if (isEncodingPass() || !src.texture->isTransferSource() || !dst.texture->isTransferDestination()) {
</ins><span class="cx">         LOG(WebGPU, "GPUCommandBuffer::copyTextureToTexture(): Invalid operation!");
</span><span class="cx">         return;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsgpucocoaGPURenderPassEncoderMetalmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPassEncoderMetal.mm (244146 => 244147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPassEncoderMetal.mm    2019-04-10 20:44:34 UTC (rev 244146)
+++ trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPassEncoderMetal.mm       2019-04-10 20:48:38 UTC (rev 244147)
</span><span class="lines">@@ -38,6 +38,7 @@
</span><span class="cx"> #import <Foundation/Foundation.h>
</span><span class="cx"> #import <Metal/Metal.h>
</span><span class="cx"> #import <wtf/BlockObjCExceptions.h>
</span><ins>+#import <wtf/CheckedArithmetic.h>
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -241,9 +242,25 @@
</span><span class="cx">     END_BLOCK_OBJC_EXCEPTIONS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void GPURenderPassEncoder::setVertexBuffers(unsigned index, Vector<Ref<GPUBuffer>>&& buffers, Vector<uint64_t>&& offsets)
</del><ins>+void GPURenderPassEncoder::setIndexBuffer(GPUBuffer& buffer, uint64_t offset)
</ins><span class="cx"> {
</span><span class="cx">     if (!m_platformRenderPassEncoder) {
</span><ins>+        LOG(WebGPU, "GPURenderPassEncoder::setIndexBuffer(): Invalid operation: Encoding is ended!");
+        return;
+    }
+    if (offset >= buffer.byteLength() || offset % 4) {
+        LOG(WebGPU, "GPURenderPassEncoder::setIndexBuffer(): Invalid offset!");
+        return;
+    }
+    ASSERT(buffer.platformBuffer());
+    // Buffer must be cached to provide it to Metal via drawIndexedPrimitives.
+    m_indexBuffer = makeRefPtr(buffer);
+    m_indexBufferOffset = offset;
+}
+
+void GPURenderPassEncoder::setVertexBuffers(unsigned index, const Vector<Ref<GPUBuffer>>& buffers, const Vector<uint64_t>& offsets)
+{
+    if (!m_platformRenderPassEncoder) {
</ins><span class="cx">         LOG(WebGPU, "GPURenderPassEncoder::setVertexBuffers(): Invalid operation: Encoding is ended!");
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="lines">@@ -254,6 +271,7 @@
</span><span class="cx"> 
</span><span class="cx">     auto mtlBuffers = buffers.map([this] (auto& buffer) {
</span><span class="cx">         commandBuffer().useBuffer(buffer.copyRef());
</span><ins>+        ASSERT(buffer->platformBuffer());
</ins><span class="cx">         return buffer->platformBuffer();
</span><span class="cx">     });
</span><span class="cx"> 
</span><span class="lines">@@ -264,7 +282,7 @@
</span><span class="cx">     END_BLOCK_OBJC_EXCEPTIONS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static MTLPrimitiveType primitiveTypeForGPUPrimitiveTopology(GPUPrimitiveTopology type)
</del><ins>+static MTLPrimitiveType mtlPrimitiveTypeForGPUPrimitiveTopology(GPUPrimitiveTopology type)
</ins><span class="cx"> {
</span><span class="cx">     switch (type) {
</span><span class="cx">     case GPUPrimitiveTopology::PointList:
</span><span class="lines">@@ -288,7 +306,6 @@
</span><span class="cx">         LOG(WebGPU, "GPURenderPassEncoder::draw(): Invalid operation: Encoding is ended!");
</span><span class="cx">         return;
</span><span class="cx">     }
</span><del>-
</del><span class="cx">     if (!m_pipeline) {
</span><span class="cx">         LOG(WebGPU, "GPURenderPassEncoder::draw(): No valid GPURenderPipeline found!");
</span><span class="cx">         return;
</span><span class="lines">@@ -296,7 +313,7 @@
</span><span class="cx"> 
</span><span class="cx">     BEGIN_BLOCK_OBJC_EXCEPTIONS;
</span><span class="cx">     [m_platformRenderPassEncoder 
</span><del>-        drawPrimitives:primitiveTypeForGPUPrimitiveTopology(m_pipeline->primitiveTopology())
</del><ins>+        drawPrimitives:mtlPrimitiveTypeForGPUPrimitiveTopology(m_pipeline->primitiveTopology())
</ins><span class="cx">         vertexStart:firstVertex
</span><span class="cx">         vertexCount:vertexCount
</span><span class="cx">         instanceCount:instanceCount
</span><span class="lines">@@ -304,6 +321,63 @@
</span><span class="cx">     END_BLOCK_OBJC_EXCEPTIONS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static MTLIndexType mtlIndexTypeForGPUIndexFormat(GPUIndexFormat format)
+{
+    switch (format) {
+    case GPUIndexFormat::Uint16:
+        return MTLIndexTypeUInt16;
+    case GPUIndexFormat::Uint32:
+        return MTLIndexTypeUInt32;
+    }
+
+    ASSERT_NOT_REACHED();
+}
+
+void GPURenderPassEncoder::drawIndexed(unsigned indexCount, unsigned instanceCount, unsigned firstIndex, int baseVertex, unsigned firstInstance)
+{
+#if !LOG_DISABLED
+    const char* const functionName = "GPURenderPassEncoder::drawIndexed()";
+#endif
+    if (!m_platformRenderPassEncoder) {
+        LOG(WebGPU, "%s: Invalid operation: Encoding is ended!", functionName);
+        return;
+    }
+    if (!m_pipeline) {
+        LOG(WebGPU, "%s: No valid GPURenderPipeline found!", functionName);
+        return;
+    }
+    if (!m_pipeline->indexFormat()) {
+        LOG(WebGPU, "%s: No GPUIndexFormat specified!", functionName);
+        return;
+    }
+    if (!m_indexBuffer || !m_indexBuffer->platformBuffer()) {
+        LOG(WebGPU, "%s: No valid index buffer set!", functionName);
+        return;
+    }
+
+    auto indexByteSize = (m_pipeline->indexFormat() == GPUIndexFormat::Uint16) ? sizeof(uint16_t) : sizeof(uint32_t);
+    uint64_t firstIndexOffset = firstIndex * indexByteSize;
+    auto totalOffset = checkedSum<uint64_t>(firstIndexOffset, m_indexBufferOffset);
+    if (totalOffset.hasOverflowed() || totalOffset >= m_indexBuffer->byteLength()) {
+        LOG(WebGPU, "%s: Invalid firstIndex!", functionName);
+        return;
+    }
+
+    commandBuffer().useBuffer(makeRef(*m_indexBuffer));
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+    [m_platformRenderPassEncoder
+        drawIndexedPrimitives:mtlPrimitiveTypeForGPUPrimitiveTopology(m_pipeline->primitiveTopology())
+        indexCount:indexCount
+        indexType:mtlIndexTypeForGPUIndexFormat(*m_pipeline->indexFormat())
+        indexBuffer:m_indexBuffer->platformBuffer()
+        indexBufferOffset:totalOffset.unsafeGet()
+        instanceCount:instanceCount
+        baseVertex:baseVertex
+        baseInstance:firstInstance];
+    END_BLOCK_OBJC_EXCEPTIONS;
+}
+
</ins><span class="cx"> #if USE(METAL)
</span><span class="cx"> 
</span><span class="cx"> void GPURenderPassEncoder::useResource(const MTLResource *resource, unsigned usage)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsgpucocoaGPURenderPipelineMetalmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm (244146 => 244147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm       2019-04-10 20:44:34 UTC (rev 244146)
+++ trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm  2019-04-10 20:48:38 UTC (rev 244147)
</span><span class="lines">@@ -517,13 +517,14 @@
</span><span class="cx">     if (!pipeline)
</span><span class="cx">         return nullptr;
</span><span class="cx"> 
</span><del>-    return adoptRef(new GPURenderPipeline(WTFMove(depthStencil), WTFMove(pipeline), descriptor.primitiveTopology));
</del><ins>+    return adoptRef(new GPURenderPipeline(WTFMove(depthStencil), WTFMove(pipeline), descriptor.primitiveTopology, descriptor.inputState.indexFormat));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-GPURenderPipeline::GPURenderPipeline(RetainPtr<MTLDepthStencilState>&& depthStencil, RetainPtr<MTLRenderPipelineState>&& pipeline, GPUPrimitiveTopology topology)
</del><ins>+GPURenderPipeline::GPURenderPipeline(RetainPtr<MTLDepthStencilState>&& depthStencil, RetainPtr<MTLRenderPipelineState>&& pipeline, GPUPrimitiveTopology topology, Optional<GPUIndexFormat> format)
</ins><span class="cx">     : m_depthStencilState(WTFMove(depthStencil))
</span><span class="cx">     , m_platformRenderPipeline(WTFMove(pipeline))
</span><span class="cx">     , m_primitiveTopology(topology)
</span><ins>+    , m_indexFormat(format)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>