[Web GPU] Indexed drawing and GPUCommandEncoder crash prevention
[WebKit-https.git] / Source / WebCore / Modules / webgpu / WebGPURenderPassEncoder.cpp
1 /*
2  * Copyright (C) 2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "WebGPURenderPassEncoder.h"
28
29 #if ENABLE(WEBGPU)
30
31 #include "GPUColor.h"
32 #include "GPULimits.h"
33 #include "GPUProgrammablePassEncoder.h"
34 #include "GPURenderPassEncoder.h"
35 #include "Logging.h"
36 #include "WebGPUBuffer.h"
37 #include "WebGPURenderPipeline.h"
38
39 namespace WebCore {
40
41 Ref<WebGPURenderPassEncoder> WebGPURenderPassEncoder::create(RefPtr<GPURenderPassEncoder>&& encoder)
42 {
43     return adoptRef(*new WebGPURenderPassEncoder(WTFMove(encoder)));
44 }
45
46 WebGPURenderPassEncoder::WebGPURenderPassEncoder(RefPtr<GPURenderPassEncoder>&& encoder)
47     : m_passEncoder { WTFMove(encoder) }
48 {
49 }
50
51 void WebGPURenderPassEncoder::setPipeline(const WebGPURenderPipeline& pipeline)
52 {
53     if (!m_passEncoder) {
54         LOG(WebGPU, "GPURenderPassEncoder::setPipeline(): Invalid operation!");
55         return;
56     }
57     if (!pipeline.renderPipeline()) {
58         LOG(WebGPU, "GPURenderPassEncoder::setPipeline(): Invalid pipeline!");
59         return;
60     }
61     m_passEncoder->setPipeline(makeRef(*pipeline.renderPipeline()));
62 }
63
64 void WebGPURenderPassEncoder::setBlendColor(const GPUColor& color)
65 {
66     if (!m_passEncoder) {
67         LOG(WebGPU, "GPURenderPassEncoder::setBlendColor(): Invalid operation!");
68         return;
69     }
70     m_passEncoder->setBlendColor(color);
71 }
72
73 void WebGPURenderPassEncoder::setViewport(float x, float y, float width, float height, float minDepth, float maxDepth)
74 {
75     if (!m_passEncoder) {
76         LOG(WebGPU, "GPURenderPassEncoder::setViewport(): Invalid operation!");
77         return;
78     }
79     m_passEncoder->setViewport(x, y, width, height, minDepth, maxDepth);
80 }
81
82 void WebGPURenderPassEncoder::setScissorRect(unsigned x, unsigned y, unsigned width, unsigned height)
83 {
84     if (!m_passEncoder) {
85         LOG(WebGPU, "GPURenderPassEncoder::setScissorRect(): Invalid operation!");
86         return;
87     }
88     if (!width || !height) {
89         LOG(WebGPU, "GPURenderPassEncoder::setScissorRect(): Width or height must be greater than 0!");
90         return;
91     }
92     m_passEncoder->setScissorRect(x, y, width, height);
93 }
94
95 void WebGPURenderPassEncoder::setIndexBuffer(WebGPUBuffer& buffer, uint64_t offset)
96 {
97     if (!m_passEncoder) {
98         LOG(WebGPU, "GPURenderPassEncoder::setIndexBuffer(): Invalid operation!");
99         return;
100     }
101     if (!buffer.buffer() || !buffer.buffer()->isIndex()) {
102         LOG(WebGPU, "GPURenderPassEncoder::setIndexBuffer(): Invalid GPUBuffer!");
103         return;
104     }
105
106     m_passEncoder->setIndexBuffer(*buffer.buffer(), offset);
107 }
108
109 void WebGPURenderPassEncoder::setVertexBuffers(unsigned startSlot, const Vector<RefPtr<WebGPUBuffer>>& buffers, const Vector<uint64_t>& offsets)
110 {
111 #if !LOG_DISABLED
112     const char* const functionName = "GPURenderPassEncoder::setVertexBuffers()";
113 #endif
114     if (!m_passEncoder) {
115         LOG(WebGPU, "%s: Invalid operation!", functionName);
116         return;
117     }
118     if (buffers.isEmpty() || buffers.size() != offsets.size()) {
119         LOG(WebGPU, "%s: Invalid number of buffers or offsets!", functionName);
120         return;
121     }
122     if (startSlot + buffers.size() > maxVertexBuffers) {
123         LOG(WebGPU, "%s: Invalid startSlot %u for %lu buffers!", functionName, startSlot, buffers.size());
124         return;
125     }
126
127     Vector<Ref<GPUBuffer>> gpuBuffers;
128     gpuBuffers.reserveCapacity(buffers.size());
129
130     for (auto& buffer : buffers) {
131         if (!buffer || !buffer->buffer()) {
132             LOG(WebGPU, "%s: Invalid or destroyed buffer in list!", functionName);
133             return;
134         }
135
136         if (!buffer->buffer()->isVertex()) {
137             LOG(WebGPU, "%s: Buffer was not created with VERTEX usage!", functionName);
138             return;
139         }
140
141         gpuBuffers.uncheckedAppend(makeRef(*buffer->buffer()));
142     }
143
144     m_passEncoder->setVertexBuffers(startSlot, gpuBuffers, offsets);
145 }
146
147 void WebGPURenderPassEncoder::draw(unsigned vertexCount, unsigned instanceCount, unsigned firstVertex, unsigned firstInstance)
148 {
149     if (!m_passEncoder) {
150         LOG(WebGPU, "GPURenderPassEncoder::draw(): Invalid operation!");
151         return;
152     }
153     // FIXME: What kind of validation do we need to handle here?
154     m_passEncoder->draw(vertexCount, instanceCount, firstVertex, firstInstance);
155 }
156
157 void WebGPURenderPassEncoder::drawIndexed(unsigned indexCount, unsigned instanceCount, unsigned firstIndex, int baseVertex, unsigned firstInstance)
158 {
159     if (!m_passEncoder) {
160         LOG(WebGPU, "GPURenderPassEncoder::draw(): Invalid operation!");
161         return;
162     }
163     // FIXME: Add Web GPU validation.
164     m_passEncoder->drawIndexed(indexCount, instanceCount, firstIndex, baseVertex, firstInstance);
165 }
166
167 GPUProgrammablePassEncoder* WebGPURenderPassEncoder::passEncoder()
168 {
169     return m_passEncoder.get();
170 }
171
172 const GPUProgrammablePassEncoder* WebGPURenderPassEncoder::passEncoder() const
173 {
174     return m_passEncoder.get();
175 }
176
177 } // namespace WebCore
178
179 #endif // ENABLE(WEBGPU)