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/GrMesh.h"
12 #include "src/gpu/GrOpFlushState.h"
13 #include "src/gpu/GrPipeline.h"
14 #include "src/gpu/GrRenderTargetPriv.h"
15 #include "src/gpu/GrTexturePriv.h"
16 #include "src/gpu/dawn/GrDawnBuffer.h"
17 #include "src/gpu/dawn/GrDawnGpu.h"
18 #include "src/gpu/dawn/GrDawnProgramBuilder.h"
19 #include "src/gpu/dawn/GrDawnRenderTarget.h"
20 #include "src/gpu/dawn/GrDawnStencilAttachment.h"
21 #include "src/gpu/dawn/GrDawnTexture.h"
22 #include "src/gpu/dawn/GrDawnUtil.h"
23 #include "src/sksl/SkSLCompiler.h"
24 
25 ////////////////////////////////////////////////////////////////////////////////
26 
to_dawn_load_op(GrLoadOp loadOp)27 static dawn::LoadOp to_dawn_load_op(GrLoadOp loadOp) {
28     switch (loadOp) {
29         case GrLoadOp::kLoad:
30             return dawn::LoadOp::Load;
31         case GrLoadOp::kDiscard:
32             // Use LoadOp::Load to emulate DontCare.
33             // Dawn doesn't have DontCare, for security reasons.
34             // Load should be equivalent to DontCare for desktop; Clear would
35             // probably be better for tilers. If Dawn does add DontCare
36             // as an extension, use it here.
37             return dawn::LoadOp::Load;
38         case GrLoadOp::kClear:
39             return dawn::LoadOp::Clear;
40         default:
41             SK_ABORT("Invalid LoadOp");
42     }
43 }
44 
GrDawnOpsRenderPass(GrDawnGpu * gpu,GrRenderTarget * rt,GrSurfaceOrigin origin,const LoadAndStoreInfo & colorInfo,const StencilLoadAndStoreInfo & stencilInfo)45 GrDawnOpsRenderPass::GrDawnOpsRenderPass(GrDawnGpu* gpu, GrRenderTarget* rt, GrSurfaceOrigin origin,
46                                          const LoadAndStoreInfo& colorInfo,
47                                          const StencilLoadAndStoreInfo& stencilInfo)
48         : INHERITED(rt, origin)
49         , fGpu(gpu)
50         , fColorInfo(colorInfo) {
51     fEncoder = fGpu->device().CreateCommandEncoder();
52     dawn::LoadOp colorOp = to_dawn_load_op(colorInfo.fLoadOp);
53     dawn::LoadOp stencilOp = to_dawn_load_op(stencilInfo.fLoadOp);
54     fPassEncoder = beginRenderPass(colorOp, stencilOp);
55 }
56 
beginRenderPass(dawn::LoadOp colorOp,dawn::LoadOp stencilOp)57 dawn::RenderPassEncoder GrDawnOpsRenderPass::beginRenderPass(dawn::LoadOp colorOp,
58                                                              dawn::LoadOp stencilOp) {
59     dawn::Texture texture = static_cast<GrDawnRenderTarget*>(fRenderTarget)->texture();
60     auto stencilAttachment = static_cast<GrDawnStencilAttachment*>(
61         fRenderTarget->renderTargetPriv().getStencilAttachment());
62     dawn::TextureView colorView = texture.CreateView();
63     const float *c = fColorInfo.fClearColor.vec();
64 
65     dawn::RenderPassColorAttachmentDescriptor colorAttachment;
66     colorAttachment.attachment = colorView;
67     colorAttachment.resolveTarget = nullptr;
68     colorAttachment.clearColor = { c[0], c[1], c[2], c[3] };
69     colorAttachment.loadOp = colorOp;
70     colorAttachment.storeOp = dawn::StoreOp::Store;
71     dawn::RenderPassColorAttachmentDescriptor* colorAttachments = { &colorAttachment };
72     dawn::RenderPassDescriptor renderPassDescriptor;
73     renderPassDescriptor.colorAttachmentCount = 1;
74     renderPassDescriptor.colorAttachments = colorAttachments;
75     if (stencilAttachment) {
76         dawn::RenderPassDepthStencilAttachmentDescriptor depthStencilAttachment;
77         depthStencilAttachment.attachment = stencilAttachment->view();
78         depthStencilAttachment.depthLoadOp = stencilOp;
79         depthStencilAttachment.stencilLoadOp = stencilOp;
80         depthStencilAttachment.clearDepth = 1.0f;
81         depthStencilAttachment.clearStencil = 0;
82         depthStencilAttachment.depthStoreOp = dawn::StoreOp::Store;
83         depthStencilAttachment.stencilStoreOp = dawn::StoreOp::Store;
84         renderPassDescriptor.depthStencilAttachment = &depthStencilAttachment;
85     } else {
86         renderPassDescriptor.depthStencilAttachment = nullptr;
87     }
88     return fEncoder.BeginRenderPass(&renderPassDescriptor);
89 }
90 
~GrDawnOpsRenderPass()91 GrDawnOpsRenderPass::~GrDawnOpsRenderPass() {
92 }
93 
gpu()94 GrGpu* GrDawnOpsRenderPass::gpu() { return fGpu; }
95 
end()96 void GrDawnOpsRenderPass::end() {
97     fPassEncoder.EndPass();
98 }
99 
submit()100 void GrDawnOpsRenderPass::submit() {
101     fGpu->appendCommandBuffer(fEncoder.Finish());
102 }
103 
insertEventMarker(const char * msg)104 void GrDawnOpsRenderPass::insertEventMarker(const char* msg) {
105     SkASSERT(!"unimplemented");
106 }
107 
onClearStencilClip(const GrFixedClip & clip,bool insideStencilMask)108 void GrDawnOpsRenderPass::onClearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
109     fPassEncoder.EndPass();
110     fPassEncoder = beginRenderPass(dawn::LoadOp::Load, dawn::LoadOp::Clear);
111 }
112 
onClear(const GrFixedClip & clip,const SkPMColor4f & color)113 void GrDawnOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& color) {
114     fPassEncoder.EndPass();
115     fPassEncoder = beginRenderPass(dawn::LoadOp::Clear, dawn::LoadOp::Load);
116 }
117 
118 ////////////////////////////////////////////////////////////////////////////////
119 
inlineUpload(GrOpFlushState * state,GrDeferredTextureUploadFn & upload)120 void GrDawnOpsRenderPass::inlineUpload(GrOpFlushState* state,
121                                        GrDeferredTextureUploadFn& upload) {
122     SkASSERT(!"unimplemented");
123 }
124 
125 ////////////////////////////////////////////////////////////////////////////////
126 
setScissorState(const GrProgramInfo & programInfo)127 void GrDawnOpsRenderPass::setScissorState(const GrProgramInfo& programInfo) {
128     SkIRect rect;
129     if (programInfo.pipeline().isScissorEnabled()) {
130         constexpr SkIRect kBogusScissor{0, 0, 1, 1};
131         rect = programInfo.hasFixedScissor() ? programInfo.fixedScissor() : kBogusScissor;
132         if (kBottomLeft_GrSurfaceOrigin == fOrigin) {
133             rect.setXYWH(rect.x(), fRenderTarget->height() - rect.bottom(),
134                          rect.width(), rect.height());
135         }
136     } else {
137         rect = SkIRect::MakeWH(fRenderTarget->width(), fRenderTarget->height());
138     }
139     fPassEncoder.SetScissorRect(rect.x(), rect.y(), rect.width(), rect.height());
140 }
141 
applyState(const GrProgramInfo & programInfo,const GrPrimitiveType primitiveType)142 void GrDawnOpsRenderPass::applyState(const GrProgramInfo& programInfo,
143                                      const GrPrimitiveType primitiveType) {
144     sk_sp<GrDawnProgram> program = fGpu->getOrCreateRenderPipeline(fRenderTarget,
145                                                                    programInfo,
146                                                                    primitiveType);
147     auto bindGroup = program->setData(fGpu, fRenderTarget, programInfo);
148     fPassEncoder.SetPipeline(program->fRenderPipeline);
149     fPassEncoder.SetBindGroup(0, bindGroup, 0, nullptr);
150     const GrPipeline& pipeline = programInfo.pipeline();
151     if (pipeline.isStencilEnabled()) {
152         fPassEncoder.SetStencilReference(pipeline.getUserStencil()->fFront.fRef);
153     }
154     GrXferProcessor::BlendInfo blendInfo = pipeline.getXferProcessor().getBlendInfo();
155     const float* c = blendInfo.fBlendConstant.vec();
156     dawn::Color color{c[0], c[1], c[2], c[3]};
157     fPassEncoder.SetBlendColor(&color);
158     this->setScissorState(programInfo);
159 }
160 
onDraw(const GrProgramInfo & programInfo,const GrMesh meshes[],int meshCount,const SkRect & bounds)161 void GrDawnOpsRenderPass::onDraw(const GrProgramInfo& programInfo,
162                                  const GrMesh meshes[],
163                                  int meshCount,
164                                  const SkRect& bounds) {
165     if (!meshCount) {
166         return;
167     }
168     for (int i = 0; i < meshCount; ++i) {
169         applyState(programInfo, meshes[0].primitiveType());
170         meshes[i].sendToGpu(this);
171     }
172 }
173 
sendInstancedMeshToGpu(GrPrimitiveType,const GrBuffer * vertexBuffer,int vertexCount,int baseVertex,const GrBuffer * instanceBuffer,int instanceCount,int baseInstance)174 void GrDawnOpsRenderPass::sendInstancedMeshToGpu(GrPrimitiveType,
175                                                  const GrBuffer* vertexBuffer,
176                                                  int vertexCount,
177                                                  int baseVertex,
178                                                  const GrBuffer* instanceBuffer,
179                                                  int instanceCount,
180                                                  int baseInstance) {
181     dawn::Buffer vb = static_cast<const GrDawnBuffer*>(vertexBuffer)->get();
182     fPassEncoder.SetVertexBuffer(0, vb);
183     fPassEncoder.Draw(vertexCount, 1, baseVertex, baseInstance);
184     fGpu->stats()->incNumDraws();
185 }
186 
sendIndexedInstancedMeshToGpu(GrPrimitiveType,const GrBuffer * indexBuffer,int indexCount,int baseIndex,const GrBuffer * vertexBuffer,int baseVertex,const GrBuffer * instanceBuffer,int instanceCount,int baseInstance,GrPrimitiveRestart restart)187 void GrDawnOpsRenderPass::sendIndexedInstancedMeshToGpu(GrPrimitiveType,
188                                                         const GrBuffer* indexBuffer,
189                                                         int indexCount,
190                                                         int baseIndex,
191                                                         const GrBuffer* vertexBuffer,
192                                                         int baseVertex,
193                                                         const GrBuffer* instanceBuffer,
194                                                         int instanceCount,
195                                                         int baseInstance,
196                                                         GrPrimitiveRestart restart) {
197     dawn::Buffer vb = static_cast<const GrDawnBuffer*>(vertexBuffer)->get();
198     dawn::Buffer ib = static_cast<const GrDawnBuffer*>(indexBuffer)->get();
199     fPassEncoder.SetIndexBuffer(ib);
200     fPassEncoder.SetVertexBuffer(0, vb);
201     fPassEncoder.DrawIndexed(indexCount, 1, baseIndex, baseVertex, baseInstance);
202     fGpu->stats()->incNumDraws();
203 }
204