1 /*
2 * Copyright 2019 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/dawn/GrDawnOpsRenderPass.h"
9
10 #include "src/gpu/GrFixedClip.h"
11 #include "src/gpu/GrOpFlushState.h"
12 #include "src/gpu/GrPipeline.h"
13 #include "src/gpu/GrRenderTargetPriv.h"
14 #include "src/gpu/GrTexturePriv.h"
15 #include "src/gpu/dawn/GrDawnBuffer.h"
16 #include "src/gpu/dawn/GrDawnGpu.h"
17 #include "src/gpu/dawn/GrDawnProgramBuilder.h"
18 #include "src/gpu/dawn/GrDawnRenderTarget.h"
19 #include "src/gpu/dawn/GrDawnStencilAttachment.h"
20 #include "src/gpu/dawn/GrDawnTexture.h"
21 #include "src/gpu/dawn/GrDawnUtil.h"
22 #include "src/sksl/SkSLCompiler.h"
23
24 ////////////////////////////////////////////////////////////////////////////////
25
to_dawn_load_op(GrLoadOp loadOp)26 static wgpu::LoadOp to_dawn_load_op(GrLoadOp loadOp) {
27 switch (loadOp) {
28 case GrLoadOp::kLoad:
29 return wgpu::LoadOp::Load;
30 case GrLoadOp::kDiscard:
31 // Use LoadOp::Load to emulate DontCare.
32 // Dawn doesn't have DontCare, for security reasons.
33 // Load should be equivalent to DontCare for desktop; Clear would
34 // probably be better for tilers. If Dawn does add DontCare
35 // as an extension, use it here.
36 return wgpu::LoadOp::Load;
37 case GrLoadOp::kClear:
38 return wgpu::LoadOp::Clear;
39 default:
40 SK_ABORT("Invalid LoadOp");
41 }
42 }
43
GrDawnOpsRenderPass(GrDawnGpu * gpu,GrRenderTarget * rt,GrSurfaceOrigin origin,const LoadAndStoreInfo & colorInfo,const StencilLoadAndStoreInfo & stencilInfo)44 GrDawnOpsRenderPass::GrDawnOpsRenderPass(GrDawnGpu* gpu, GrRenderTarget* rt, GrSurfaceOrigin origin,
45 const LoadAndStoreInfo& colorInfo,
46 const StencilLoadAndStoreInfo& stencilInfo)
47 : INHERITED(rt, origin)
48 , fGpu(gpu)
49 , fColorInfo(colorInfo) {
50 fEncoder = fGpu->device().CreateCommandEncoder();
51 wgpu::LoadOp colorOp = to_dawn_load_op(colorInfo.fLoadOp);
52 wgpu::LoadOp stencilOp = to_dawn_load_op(stencilInfo.fLoadOp);
53 fPassEncoder = beginRenderPass(colorOp, stencilOp);
54 }
55
beginRenderPass(wgpu::LoadOp colorOp,wgpu::LoadOp stencilOp)56 wgpu::RenderPassEncoder GrDawnOpsRenderPass::beginRenderPass(wgpu::LoadOp colorOp,
57 wgpu::LoadOp stencilOp) {
58 auto stencilAttachment = static_cast<GrDawnStencilAttachment*>(
59 fRenderTarget->renderTargetPriv().getStencilAttachment());
60 const float *c = fColorInfo.fClearColor.vec();
61
62 wgpu::RenderPassColorAttachmentDescriptor colorAttachment;
63 colorAttachment.attachment = static_cast<GrDawnRenderTarget*>(fRenderTarget)->textureView();
64 colorAttachment.resolveTarget = nullptr;
65 colorAttachment.clearColor = { c[0], c[1], c[2], c[3] };
66 colorAttachment.loadOp = colorOp;
67 colorAttachment.storeOp = wgpu::StoreOp::Store;
68 wgpu::RenderPassColorAttachmentDescriptor* colorAttachments = { &colorAttachment };
69 wgpu::RenderPassDescriptor renderPassDescriptor;
70 renderPassDescriptor.colorAttachmentCount = 1;
71 renderPassDescriptor.colorAttachments = colorAttachments;
72 if (stencilAttachment) {
73 wgpu::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
74 depthStencilAttachment.attachment = stencilAttachment->view();
75 depthStencilAttachment.depthLoadOp = stencilOp;
76 depthStencilAttachment.stencilLoadOp = stencilOp;
77 depthStencilAttachment.clearDepth = 1.0f;
78 depthStencilAttachment.clearStencil = 0;
79 depthStencilAttachment.depthStoreOp = wgpu::StoreOp::Store;
80 depthStencilAttachment.stencilStoreOp = wgpu::StoreOp::Store;
81 renderPassDescriptor.depthStencilAttachment = &depthStencilAttachment;
82 } else {
83 renderPassDescriptor.depthStencilAttachment = nullptr;
84 }
85 return fEncoder.BeginRenderPass(&renderPassDescriptor);
86 }
87
~GrDawnOpsRenderPass()88 GrDawnOpsRenderPass::~GrDawnOpsRenderPass() {
89 }
90
gpu()91 GrGpu* GrDawnOpsRenderPass::gpu() { return fGpu; }
92
submit()93 void GrDawnOpsRenderPass::submit() {
94 fGpu->appendCommandBuffer(fEncoder.Finish());
95 }
96
onClearStencilClip(const GrFixedClip & clip,bool insideStencilMask)97 void GrDawnOpsRenderPass::onClearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
98 fPassEncoder.EndPass();
99 fPassEncoder = beginRenderPass(wgpu::LoadOp::Load, wgpu::LoadOp::Clear);
100 }
101
onClear(const GrFixedClip & clip,const SkPMColor4f & color)102 void GrDawnOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& color) {
103 fPassEncoder.EndPass();
104 fPassEncoder = beginRenderPass(wgpu::LoadOp::Clear, wgpu::LoadOp::Load);
105 }
106
107 ////////////////////////////////////////////////////////////////////////////////
108
inlineUpload(GrOpFlushState * state,GrDeferredTextureUploadFn & upload)109 void GrDawnOpsRenderPass::inlineUpload(GrOpFlushState* state,
110 GrDeferredTextureUploadFn& upload) {
111 SkASSERT(!"unimplemented");
112 }
113
114 ////////////////////////////////////////////////////////////////////////////////
115
applyState(GrDawnProgram * program,const GrProgramInfo & programInfo)116 void GrDawnOpsRenderPass::applyState(GrDawnProgram* program, const GrProgramInfo& programInfo) {
117 auto bindGroup = program->setUniformData(fGpu, fRenderTarget, programInfo);
118 fPassEncoder.SetPipeline(program->fRenderPipeline);
119 fPassEncoder.SetBindGroup(0, bindGroup, 0, nullptr);
120 const GrPipeline& pipeline = programInfo.pipeline();
121 if (pipeline.isStencilEnabled()) {
122 fPassEncoder.SetStencilReference(pipeline.getUserStencil()->fCCWFace.fRef);
123 }
124 GrXferProcessor::BlendInfo blendInfo = pipeline.getXferProcessor().getBlendInfo();
125 const float* c = blendInfo.fBlendConstant.vec();
126 wgpu::Color color{c[0], c[1], c[2], c[3]};
127 fPassEncoder.SetBlendColor(&color);
128 if (!programInfo.pipeline().isScissorTestEnabled()) {
129 // "Disable" scissor by setting it to the full pipeline bounds.
130 SkIRect rect = SkIRect::MakeWH(fRenderTarget->width(), fRenderTarget->height());
131 fPassEncoder.SetScissorRect(rect.x(), rect.y(), rect.width(), rect.height());
132 }
133 }
134
onEnd()135 void GrDawnOpsRenderPass::onEnd() {
136 fPassEncoder.EndPass();
137 }
138
onBindPipeline(const GrProgramInfo & programInfo,const SkRect & drawBounds)139 bool GrDawnOpsRenderPass::onBindPipeline(const GrProgramInfo& programInfo,
140 const SkRect& drawBounds) {
141 fCurrentProgram = fGpu->getOrCreateRenderPipeline(fRenderTarget, programInfo);
142 this->applyState(fCurrentProgram.get(), programInfo);
143 return true;
144 }
145
onSetScissorRect(const SkIRect & scissor)146 void GrDawnOpsRenderPass::onSetScissorRect(const SkIRect& scissor) {
147 SkIRect rect;
148 SkIRect currentPipelineBounds =
149 SkIRect::MakeWH(fRenderTarget->width(), fRenderTarget->height());
150 if (!rect.intersect(currentPipelineBounds, scissor)) {
151 rect = SkIRect::MakeEmpty();
152 }
153 fPassEncoder.SetScissorRect(rect.x(), rect.y(), rect.width(), rect.height());
154 }
155
onBindTextures(const GrPrimitiveProcessor & primProc,const GrSurfaceProxy * const primProcTextures[],const GrPipeline & pipeline)156 bool GrDawnOpsRenderPass::onBindTextures(const GrPrimitiveProcessor& primProc,
157 const GrSurfaceProxy* const primProcTextures[],
158 const GrPipeline& pipeline) {
159 auto bindGroup = fCurrentProgram->setTextures(fGpu, primProc, pipeline, primProcTextures);
160 fPassEncoder.SetBindGroup(1, bindGroup, 0, nullptr);
161 return true;
162 }
163
onBindBuffers(const GrBuffer * indexBuffer,const GrBuffer * instanceBuffer,const GrBuffer * vertexBuffer,GrPrimitiveRestart)164 void GrDawnOpsRenderPass::onBindBuffers(const GrBuffer* indexBuffer, const GrBuffer* instanceBuffer,
165 const GrBuffer* vertexBuffer, GrPrimitiveRestart) {
166 if (vertexBuffer) {
167 wgpu::Buffer vertex = static_cast<const GrDawnBuffer*>(vertexBuffer)->get();
168 fPassEncoder.SetVertexBuffer(0, vertex);
169 }
170 if (instanceBuffer) {
171 wgpu::Buffer instance = static_cast<const GrDawnBuffer*>(instanceBuffer)->get();
172 fPassEncoder.SetVertexBuffer(1, instance);
173 }
174 if (indexBuffer) {
175 wgpu::Buffer index = static_cast<const GrDawnBuffer*>(indexBuffer)->get();
176 fPassEncoder.SetIndexBuffer(index);
177 }
178 }
179
onDraw(int vertexCount,int baseVertex)180 void GrDawnOpsRenderPass::onDraw(int vertexCount, int baseVertex) {
181 this->onDrawInstanced(1, 0, vertexCount, baseVertex);
182 }
183
onDrawInstanced(int instanceCount,int baseInstance,int vertexCount,int baseVertex)184 void GrDawnOpsRenderPass::onDrawInstanced(int instanceCount, int baseInstance,
185 int vertexCount, int baseVertex) {
186 fPassEncoder.Draw(vertexCount, instanceCount, baseVertex, baseInstance);
187 fGpu->stats()->incNumDraws();
188 }
189
onDrawIndexed(int indexCount,int baseIndex,uint16_t minIndexValue,uint16_t maxIndexValue,int baseVertex)190 void GrDawnOpsRenderPass::onDrawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue,
191 uint16_t maxIndexValue, int baseVertex) {
192 this->onDrawIndexedInstanced(indexCount, baseIndex, 1, 0, baseVertex);
193 }
194
onDrawIndexedInstanced(int indexCount,int baseIndex,int instanceCount,int baseInstance,int baseVertex)195 void GrDawnOpsRenderPass::onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
196 int baseInstance, int baseVertex) {
197 fPassEncoder.DrawIndexed(indexCount, instanceCount, baseIndex, baseVertex, baseInstance);
198 fGpu->stats()->incNumDraws();
199 }
200