Diff
Modified: trunk/LayoutTests/ChangeLog (244146 => 244147)
--- trunk/LayoutTests/ChangeLog 2019-04-10 20:44:34 UTC (rev 244146)
+++ trunk/LayoutTests/ChangeLog 2019-04-10 20:48:38 UTC (rev 244147)
@@ -1,3 +1,15 @@
+2019-04-10 Justin Fan <justin_...@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.
+
2019-04-10 Megan Gardner <megan_gard...@apple.com>
Fix text autoscrolling when typing in modern webkit
Added: trunk/LayoutTests/webgpu/draw-indexed-triangles-expected.html (0 => 244147)
--- 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)
@@ -0,0 +1,12 @@
+<!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>
\ No newline at end of file
Added: trunk/LayoutTests/webgpu/draw-indexed-triangles.html (0 => 244147)
--- 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)
@@ -0,0 +1,122 @@
+<!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=""
+<p>Pass if square canvas below is completely green.</p>
+<canvas width="400" height="400"></canvas>
+<script src=""
+<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>
\ No newline at end of file
Modified: trunk/Source/WebCore/ChangeLog (244146 => 244147)
--- 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)
@@ -1,3 +1,49 @@
+2019-04-10 Justin Fan <justin_...@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):
+
2019-04-09 Ryosuke Niwa <rn...@webkit.org>
OfflineAudioDestinationNode::startRendering leaks OfflineAudioDestinationNode if offlineRender exists early
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPUCommandEncoder.cpp (244146 => 244147)
--- 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)
@@ -167,7 +167,7 @@
Ref<WebGPUCommandBuffer> WebGPUCommandEncoder::finish()
{
- if (!m_commandBuffer) {
+ if (!m_commandBuffer || m_commandBuffer->isEncodingPass()) {
LOG(WebGPU, "WebGPUCommandEncoder::finish(): Invalid operation!");
return WebGPUCommandBuffer::create(nullptr);
}
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp (244146 => 244147)
--- 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)
@@ -92,8 +92,22 @@
m_passEncoder->setScissorRect(x, y, width, height);
}
-void WebGPURenderPassEncoder::setVertexBuffers(unsigned startSlot, Vector<RefPtr<WebGPUBuffer>>&& buffers, Vector<uint64_t>&& offsets)
+void WebGPURenderPassEncoder::setIndexBuffer(WebGPUBuffer& buffer, uint64_t offset)
{
+ 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)
+{
#if !LOG_DISABLED
const char* const functionName = "GPURenderPassEncoder::setVertexBuffers()";
#endif
@@ -113,7 +127,7 @@
Vector<Ref<GPUBuffer>> gpuBuffers;
gpuBuffers.reserveCapacity(buffers.size());
- for (const auto& buffer : buffers) {
+ for (auto& buffer : buffers) {
if (!buffer || !buffer->buffer()) {
LOG(WebGPU, "%s: Invalid or destroyed buffer in list!", functionName);
return;
@@ -127,7 +141,7 @@
gpuBuffers.uncheckedAppend(makeRef(*buffer->buffer()));
}
- m_passEncoder->setVertexBuffers(startSlot, WTFMove(gpuBuffers), WTFMove(offsets));
+ m_passEncoder->setVertexBuffers(startSlot, gpuBuffers, offsets);
}
void WebGPURenderPassEncoder::draw(unsigned vertexCount, unsigned instanceCount, unsigned firstVertex, unsigned firstInstance)
@@ -140,6 +154,16 @@
m_passEncoder->draw(vertexCount, instanceCount, firstVertex, firstInstance);
}
+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);
+}
+
GPUProgrammablePassEncoder* WebGPURenderPassEncoder::passEncoder()
{
return m_passEncoder.get();
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.h (244146 => 244147)
--- 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)
@@ -48,8 +48,10 @@
void setBlendColor(const GPUColor&);
void setViewport(float x, float y, float width, float height, float minDepth, float maxDepth);
void setScissorRect(unsigned x, unsigned y, unsigned width, unsigned height);
- void setVertexBuffers(unsigned, Vector<RefPtr<WebGPUBuffer>>&&, Vector<uint64_t>&&);
+ void setIndexBuffer(WebGPUBuffer&, uint64_t offset);
+ void setVertexBuffers(unsigned startSlot, const Vector<RefPtr<WebGPUBuffer>>&, const Vector<uint64_t>& offsets);
void draw(unsigned vertexCount, unsigned instanceCount, unsigned firstVertex, unsigned firstInstance);
+ void drawIndexed(unsigned indexCount, unsigned instanceCount, unsigned firstIndex, int baseVertex, unsigned firstInstance);
private:
WebGPURenderPassEncoder(RefPtr<GPURenderPassEncoder>&&);
Modified: trunk/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.idl (244146 => 244147)
--- 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)
@@ -24,6 +24,7 @@
*/
// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
+typedef long i32;
typedef unsigned long u32;
typedef unsigned long long u64;
@@ -42,15 +43,13 @@
// Width and height must be greater than 0. Otherwise, an error will be generated.
void setScissorRect(u32 x, u32 y, u32 width, u32 height);
+ void setIndexBuffer(WebGPUBuffer buffer, u64 offset);
void setVertexBuffers(u32 startSlot, sequence<WebGPUBuffer> buffers, sequence<u64> offsets);
void draw(u32 vertexCount, u32 instanceCount, u32 firstVertex, u32 firstInstance);
+ void drawIndexed(u32 indexCount, u32 instanceCount, u32 firstIndex, i32 baseVertex, u32 firstInstance);
/* Not Yet Implemented
- void setIndexBuffer(WebGPUBuffer buffer, u64 offset);
-
- void drawIndexed(u32 indexCount, u32 instanceCount, u32 firstIndex, i32 baseVertex, u32 firstInstance);
-
- // TODO add missing commands
+ void setStencilReference(u32 reference);
*/
};
Modified: trunk/Source/WebCore/platform/graphics/gpu/GPUBuffer.h (244146 => 244147)
--- 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)
@@ -74,6 +74,7 @@
uint64_t byteLength() const { return m_byteLength; }
bool isTransferSource() const { return m_usage.contains(GPUBufferUsage::Flags::TransferSource); }
bool isTransferDestination() const { return m_usage.contains(GPUBufferUsage::Flags::TransferDestination); }
+ bool isIndex() const { return m_usage.contains(GPUBufferUsage::Flags::Index); }
bool isVertex() const { return m_usage.contains(GPUBufferUsage::Flags::Vertex); }
bool isUniform() const { return m_usage.contains(GPUBufferUsage::Flags::Uniform); }
bool isStorage() const { return m_usage.contains(GPUBufferUsage::Flags::Storage); }
Modified: trunk/Source/WebCore/platform/graphics/gpu/GPUInputStateDescriptor.h (244146 => 244147)
--- 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)
@@ -39,7 +39,7 @@
};
struct GPUInputStateDescriptor {
- GPUIndexFormat indexFormat;
+ Optional<GPUIndexFormat> indexFormat;
Vector<GPUVertexAttributeDescriptor> attributes;
Vector<GPUVertexInputDescriptor> inputs;
Modified: trunk/Source/WebCore/platform/graphics/gpu/GPURenderPassEncoder.h (244146 => 244147)
--- 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)
@@ -56,8 +56,10 @@
void setBlendColor(const GPUColor&);
void setViewport(float x, float y, float width, float height, float minDepth, float maxDepth);
void setScissorRect(unsigned x, unsigned y, unsigned width, unsigned height);
- void setVertexBuffers(unsigned, Vector<Ref<GPUBuffer>>&&, Vector<uint64_t>&&);
+ void setIndexBuffer(GPUBuffer&, uint64_t offset);
+ void setVertexBuffers(unsigned index, const Vector<Ref<GPUBuffer>>&, const Vector<uint64_t>& offsets);
void draw(unsigned vertexCount, unsigned instanceCount, unsigned firstVertex, unsigned firstInstance);
+ void drawIndexed(unsigned indexCount, unsigned instanceCount, unsigned firstIndex, int baseVertex, unsigned firstInstance);
private:
GPURenderPassEncoder(Ref<GPUCommandBuffer>&&, PlatformRenderPassEncoderSmartPtr&&);
@@ -70,6 +72,9 @@
void useResource(const MTLResource *, unsigned usage) final;
void setVertexBuffer(const MTLBuffer *, unsigned offset, unsigned index) final;
void setFragmentBuffer(const MTLBuffer *, unsigned offset, unsigned index) final;
+
+ RefPtr<GPUBuffer> m_indexBuffer;
+ uint64_t m_indexBufferOffset;
#endif // USE(METAL)
PlatformRenderPassEncoderSmartPtr m_platformRenderPassEncoder;
Modified: trunk/Source/WebCore/platform/graphics/gpu/GPURenderPipeline.h (244146 => 244147)
--- 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)
@@ -28,6 +28,7 @@
#if ENABLE(WEBGPU)
#include "GPURenderPipelineDescriptor.h"
+#include <wtf/Optional.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
#include <wtf/RetainPtr.h>
@@ -53,15 +54,17 @@
#endif
PlatformRenderPipeline* platformRenderPipeline() const { return m_platformRenderPipeline.get(); }
GPUPrimitiveTopology primitiveTopology() const { return m_primitiveTopology; }
+ Optional<GPUIndexFormat> indexFormat() const { return m_indexFormat; }
private:
#if USE(METAL)
- GPURenderPipeline(RetainPtr<MTLDepthStencilState>&&, PlatformRenderPipelineSmartPtr&&, GPUPrimitiveTopology);
+ GPURenderPipeline(RetainPtr<MTLDepthStencilState>&&, PlatformRenderPipelineSmartPtr&&, GPUPrimitiveTopology, Optional<GPUIndexFormat>);
RetainPtr<MTLDepthStencilState> m_depthStencilState;
#endif // USE(METAL)
PlatformRenderPipelineSmartPtr m_platformRenderPipeline;
GPUPrimitiveTopology m_primitiveTopology;
+ Optional<GPUIndexFormat> m_indexFormat;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPUCommandBufferMetal.mm (244146 => 244147)
--- 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)
@@ -95,7 +95,7 @@
void GPUCommandBuffer::copyBufferToBuffer(Ref<GPUBuffer>&& src, uint64_t srcOffset, Ref<GPUBuffer>&& dst, uint64_t dstOffset, uint64_t size)
{
- if (!src->isTransferSource() || !dst->isTransferDestination()) {
+ if (isEncodingPass() || !src->isTransferSource() || !dst->isTransferDestination()) {
LOG(WebGPU, "GPUCommandBuffer::copyBufferToBuffer(): Invalid operation!");
return;
}
@@ -132,7 +132,7 @@
void GPUCommandBuffer::copyBufferToTexture(GPUBufferCopyView&& srcBuffer, GPUTextureCopyView&& dstTexture, const GPUExtent3D& size)
{
- if (!srcBuffer.buffer->isTransferSource() || !dstTexture.texture->isTransferDestination()) {
+ if (isEncodingPass() || !srcBuffer.buffer->isTransferSource() || !dstTexture.texture->isTransferDestination()) {
LOG(WebGPU, "GPUComandBuffer::copyBufferToTexture(): Invalid operation!");
return;
}
@@ -170,7 +170,7 @@
void GPUCommandBuffer::copyTextureToBuffer(GPUTextureCopyView&& srcTexture, GPUBufferCopyView&& dstBuffer, const GPUExtent3D& size)
{
- if (!srcTexture.texture->isTransferSource() || !dstBuffer.buffer->isTransferDestination()) {
+ if (isEncodingPass() || !srcTexture.texture->isTransferSource() || !dstBuffer.buffer->isTransferDestination()) {
LOG(WebGPU, "GPUCommandBuffer::copyTextureToBuffer(): Invalid operation!");
return;
}
@@ -198,7 +198,7 @@
void GPUCommandBuffer::copyTextureToTexture(GPUTextureCopyView&& src, GPUTextureCopyView&& dst, const GPUExtent3D& size)
{
- if (!src.texture->isTransferSource() || !dst.texture->isTransferDestination()) {
+ if (isEncodingPass() || !src.texture->isTransferSource() || !dst.texture->isTransferDestination()) {
LOG(WebGPU, "GPUCommandBuffer::copyTextureToTexture(): Invalid operation!");
return;
}
Modified: trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPassEncoderMetal.mm (244146 => 244147)
--- 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)
@@ -38,6 +38,7 @@
#import <Foundation/Foundation.h>
#import <Metal/Metal.h>
#import <wtf/BlockObjCExceptions.h>
+#import <wtf/CheckedArithmetic.h>
namespace WebCore {
@@ -241,9 +242,25 @@
END_BLOCK_OBJC_EXCEPTIONS;
}
-void GPURenderPassEncoder::setVertexBuffers(unsigned index, Vector<Ref<GPUBuffer>>&& buffers, Vector<uint64_t>&& offsets)
+void GPURenderPassEncoder::setIndexBuffer(GPUBuffer& buffer, uint64_t offset)
{
if (!m_platformRenderPassEncoder) {
+ 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) {
LOG(WebGPU, "GPURenderPassEncoder::setVertexBuffers(): Invalid operation: Encoding is ended!");
return;
}
@@ -254,6 +271,7 @@
auto mtlBuffers = buffers.map([this] (auto& buffer) {
commandBuffer().useBuffer(buffer.copyRef());
+ ASSERT(buffer->platformBuffer());
return buffer->platformBuffer();
});
@@ -264,7 +282,7 @@
END_BLOCK_OBJC_EXCEPTIONS;
}
-static MTLPrimitiveType primitiveTypeForGPUPrimitiveTopology(GPUPrimitiveTopology type)
+static MTLPrimitiveType mtlPrimitiveTypeForGPUPrimitiveTopology(GPUPrimitiveTopology type)
{
switch (type) {
case GPUPrimitiveTopology::PointList:
@@ -288,7 +306,6 @@
LOG(WebGPU, "GPURenderPassEncoder::draw(): Invalid operation: Encoding is ended!");
return;
}
-
if (!m_pipeline) {
LOG(WebGPU, "GPURenderPassEncoder::draw(): No valid GPURenderPipeline found!");
return;
@@ -296,7 +313,7 @@
BEGIN_BLOCK_OBJC_EXCEPTIONS;
[m_platformRenderPassEncoder
- drawPrimitives:primitiveTypeForGPUPrimitiveTopology(m_pipeline->primitiveTopology())
+ drawPrimitives:mtlPrimitiveTypeForGPUPrimitiveTopology(m_pipeline->primitiveTopology())
vertexStart:firstVertex
vertexCount:vertexCount
instanceCount:instanceCount
@@ -304,6 +321,63 @@
END_BLOCK_OBJC_EXCEPTIONS;
}
+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;
+}
+
#if USE(METAL)
void GPURenderPassEncoder::useResource(const MTLResource *resource, unsigned usage)
Modified: trunk/Source/WebCore/platform/graphics/gpu/cocoa/GPURenderPipelineMetal.mm (244146 => 244147)
--- 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)
@@ -517,13 +517,14 @@
if (!pipeline)
return nullptr;
- return adoptRef(new GPURenderPipeline(WTFMove(depthStencil), WTFMove(pipeline), descriptor.primitiveTopology));
+ return adoptRef(new GPURenderPipeline(WTFMove(depthStencil), WTFMove(pipeline), descriptor.primitiveTopology, descriptor.inputState.indexFormat));
}
-GPURenderPipeline::GPURenderPipeline(RetainPtr<MTLDepthStencilState>&& depthStencil, RetainPtr<MTLRenderPipelineState>&& pipeline, GPUPrimitiveTopology topology)
+GPURenderPipeline::GPURenderPipeline(RetainPtr<MTLDepthStencilState>&& depthStencil, RetainPtr<MTLRenderPipelineState>&& pipeline, GPUPrimitiveTopology topology, Optional<GPUIndexFormat> format)
: m_depthStencilState(WTFMove(depthStencil))
, m_platformRenderPipeline(WTFMove(pipeline))
, m_primitiveTopology(topology)
+ , m_indexFormat(format)
{
}