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