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/ganesh/dawn/GrDawnOpsRenderPass.h"
9
10 #include "src/gpu/ganesh/GrNativeRect.h"
11 #include "src/gpu/ganesh/GrOpFlushState.h"
12 #include "src/gpu/ganesh/GrPipeline.h"
13 #include "src/gpu/ganesh/GrRenderTarget.h"
14 #include "src/gpu/ganesh/GrStencilSettings.h"
15 #include "src/gpu/ganesh/GrTexture.h"
16 #include "src/gpu/ganesh/dawn/GrDawnAttachment.h"
17 #include "src/gpu/ganesh/dawn/GrDawnBuffer.h"
18 #include "src/gpu/ganesh/dawn/GrDawnGpu.h"
19 #include "src/gpu/ganesh/dawn/GrDawnProgramBuilder.h"
20 #include "src/gpu/ganesh/dawn/GrDawnRenderTarget.h"
21 #include "src/gpu/ganesh/dawn/GrDawnTexture.h"
22 #include "src/gpu/ganesh/dawn/GrDawnUtil.h"
23 #include "src/sksl/SkSLCompiler.h"
24
25 ////////////////////////////////////////////////////////////////////////////////
26
to_dawn_load_op(GrLoadOp loadOp)27 static wgpu::LoadOp to_dawn_load_op(GrLoadOp loadOp) {
28 switch (loadOp) {
29 case GrLoadOp::kLoad:
30 return wgpu::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 wgpu::LoadOp::Load;
38 case GrLoadOp::kClear:
39 return wgpu::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 wgpu::LoadOp colorOp = to_dawn_load_op(colorInfo.fLoadOp);
53 wgpu::LoadOp stencilOp = to_dawn_load_op(stencilInfo.fLoadOp);
54 fPassEncoder = beginRenderPass(colorOp, stencilOp);
55 }
56
beginRenderPass(wgpu::LoadOp colorOp,wgpu::LoadOp stencilOp)57 wgpu::RenderPassEncoder GrDawnOpsRenderPass::beginRenderPass(wgpu::LoadOp colorOp,
58 wgpu::LoadOp stencilOp) {
59 if (GrTexture* tex = fRenderTarget->asTexture()) {
60 tex->markMipmapsDirty();
61 }
62 auto stencilAttachment = static_cast<GrDawnAttachment*>(fRenderTarget->getStencilAttachment());
63
64 const float* c = fColorInfo.fClearColor.data();
65
66 wgpu::RenderPassColorAttachment colorAttachment;
67 colorAttachment.view = static_cast<GrDawnRenderTarget*>(fRenderTarget)->textureView();
68 colorAttachment.resolveTarget = nullptr;
69 colorAttachment.clearValue = {c[0], c[1], c[2], c[3]};
70 colorAttachment.loadOp = colorOp;
71 colorAttachment.storeOp = wgpu::StoreOp::Store;
72 wgpu::RenderPassColorAttachment* colorAttachments = { &colorAttachment };
73 wgpu::RenderPassDescriptor renderPassDescriptor;
74 renderPassDescriptor.colorAttachmentCount = 1;
75 renderPassDescriptor.colorAttachments = colorAttachments;
76
77 wgpu::RenderPassDepthStencilAttachment depthStencilAttachment;
78 if (stencilAttachment) {
79 depthStencilAttachment.view = stencilAttachment->view();
80 depthStencilAttachment.depthLoadOp = stencilOp;
81 depthStencilAttachment.stencilLoadOp = stencilOp;
82 depthStencilAttachment.depthClearValue = 1.0f;
83 depthStencilAttachment.stencilClearValue = 0;
84 depthStencilAttachment.depthStoreOp = wgpu::StoreOp::Store;
85 depthStencilAttachment.stencilStoreOp = wgpu::StoreOp::Store;
86 renderPassDescriptor.depthStencilAttachment = &depthStencilAttachment;
87 } else {
88 renderPassDescriptor.depthStencilAttachment = nullptr;
89 }
90
91 return fEncoder.BeginRenderPass(&renderPassDescriptor);
92 }
93
~GrDawnOpsRenderPass()94 GrDawnOpsRenderPass::~GrDawnOpsRenderPass() {
95 }
96
gpu()97 GrGpu* GrDawnOpsRenderPass::gpu() { return fGpu; }
98
submit()99 void GrDawnOpsRenderPass::submit() {
100 fGpu->appendCommandBuffer(fEncoder.Finish());
101 }
102
onClearStencilClip(const GrScissorState & scissor,bool insideStencilMask)103 void GrDawnOpsRenderPass::onClearStencilClip(const GrScissorState& scissor,
104 bool insideStencilMask) {
105 SkASSERT(!scissor.enabled());
106 fPassEncoder.End();
107 fPassEncoder = beginRenderPass(wgpu::LoadOp::Load, wgpu::LoadOp::Clear);
108 }
109
onClear(const GrScissorState & scissor,std::array<float,4> color)110 void GrDawnOpsRenderPass::onClear(const GrScissorState& scissor, std::array<float, 4> color) {
111 SkASSERT(!scissor.enabled());
112 fPassEncoder.End();
113 fPassEncoder = beginRenderPass(wgpu::LoadOp::Clear, wgpu::LoadOp::Load);
114 }
115
116 ////////////////////////////////////////////////////////////////////////////////
117
inlineUpload(GrOpFlushState * state,GrDeferredTextureUploadFn & upload)118 void GrDawnOpsRenderPass::inlineUpload(GrOpFlushState* state,
119 GrDeferredTextureUploadFn& upload) {
120 fGpu->submitToGpu(false);
121 state->doUpload(upload);
122 }
123
124 ////////////////////////////////////////////////////////////////////////////////
125
126 // Our caps require there to be a single reference value for both faces. However, our stencil
127 // object asserts if the correct face getter is not queried.
get_stencil_ref(const GrProgramInfo & info)128 static uint16_t get_stencil_ref(const GrProgramInfo& info) {
129 GrStencilSettings stencilSettings = info.nonGLStencilSettings();
130 if (stencilSettings.isTwoSided()) {
131 SkASSERT(stencilSettings.postOriginCCWFace(info.origin()).fRef ==
132 stencilSettings.postOriginCWFace(info.origin()).fRef);
133 return stencilSettings.postOriginCCWFace(info.origin()).fRef;
134 } else {
135 return stencilSettings.singleSidedFace().fRef;
136 }
137 }
138
applyState(GrDawnProgram * program,const GrProgramInfo & programInfo)139 void GrDawnOpsRenderPass::applyState(GrDawnProgram* program, const GrProgramInfo& programInfo) {
140 auto bindGroup = program->setUniformData(fGpu, fRenderTarget, programInfo);
141 fPassEncoder.SetPipeline(program->fRenderPipeline);
142 fPassEncoder.SetBindGroup(0, bindGroup, 0, nullptr);
143 if (programInfo.isStencilEnabled()) {
144 fPassEncoder.SetStencilReference(get_stencil_ref(programInfo));
145 }
146 const GrPipeline& pipeline = programInfo.pipeline();
147 skgpu::BlendInfo blendInfo = pipeline.getXferProcessor().getBlendInfo();
148 const float* c = blendInfo.fBlendConstant.vec();
149 wgpu::Color color{c[0], c[1], c[2], c[3]};
150 fPassEncoder.SetBlendConstant(&color);
151 if (!programInfo.pipeline().isScissorTestEnabled()) {
152 // "Disable" scissor by setting it to the full pipeline bounds.
153 SkIRect rect = SkIRect::MakeWH(fRenderTarget->width(), fRenderTarget->height());
154 fPassEncoder.SetScissorRect(rect.x(), rect.y(), rect.width(), rect.height());
155 }
156 }
157
onEnd()158 void GrDawnOpsRenderPass::onEnd() { fPassEncoder.End(); }
159
onBindPipeline(const GrProgramInfo & programInfo,const SkRect & drawBounds)160 bool GrDawnOpsRenderPass::onBindPipeline(const GrProgramInfo& programInfo,
161 const SkRect& drawBounds) {
162 fCurrentProgram = fGpu->getOrCreateRenderPipeline(fRenderTarget, programInfo);
163 if (!fCurrentProgram) {
164 return false;
165 }
166 this->applyState(fCurrentProgram.get(), programInfo);
167 return true;
168 }
169
onSetScissorRect(const SkIRect & scissor)170 void GrDawnOpsRenderPass::onSetScissorRect(const SkIRect& scissor) {
171 // Higher-level skgpu::v1::SurfaceDrawContext and clips should have already ensured draw
172 // bounds are restricted to the render target.
173 SkASSERT(SkIRect::MakeSize(fRenderTarget->dimensions()).contains(scissor));
174 auto nativeScissorRect =
175 GrNativeRect::MakeRelativeTo(fOrigin, fRenderTarget->height(), scissor);
176 fPassEncoder.SetScissorRect(nativeScissorRect.fX, nativeScissorRect.fY,
177 nativeScissorRect.fWidth, nativeScissorRect.fHeight);
178 }
179
onBindTextures(const GrGeometryProcessor & geomProc,const GrSurfaceProxy * const geomProcTextures[],const GrPipeline & pipeline)180 bool GrDawnOpsRenderPass::onBindTextures(const GrGeometryProcessor& geomProc,
181 const GrSurfaceProxy* const geomProcTextures[],
182 const GrPipeline& pipeline) {
183 auto bindGroup = fCurrentProgram->setTextures(fGpu, geomProc, pipeline, geomProcTextures);
184 if (bindGroup) {
185 fPassEncoder.SetBindGroup(1, bindGroup, 0, nullptr);
186 }
187 return true;
188 }
189
onBindBuffers(sk_sp<const GrBuffer> indexBuffer,sk_sp<const GrBuffer> instanceBuffer,sk_sp<const GrBuffer> vertexBuffer,GrPrimitiveRestart)190 void GrDawnOpsRenderPass::onBindBuffers(sk_sp<const GrBuffer> indexBuffer,
191 sk_sp<const GrBuffer> instanceBuffer,
192 sk_sp<const GrBuffer> vertexBuffer,
193 GrPrimitiveRestart) {
194 if (vertexBuffer) {
195 wgpu::Buffer vertex = static_cast<const GrDawnBuffer*>(vertexBuffer.get())->get();
196 fPassEncoder.SetVertexBuffer(0, vertex);
197 }
198 if (instanceBuffer) {
199 wgpu::Buffer instance = static_cast<const GrDawnBuffer*>(instanceBuffer.get())->get();
200 fPassEncoder.SetVertexBuffer(1, instance);
201 }
202 if (indexBuffer) {
203 wgpu::Buffer index = static_cast<const GrDawnBuffer*>(indexBuffer.get())->get();
204 fPassEncoder.SetIndexBuffer(index, wgpu::IndexFormat::Uint16);
205 }
206 }
207
onDraw(int vertexCount,int baseVertex)208 void GrDawnOpsRenderPass::onDraw(int vertexCount, int baseVertex) {
209 this->onDrawInstanced(1, 0, vertexCount, baseVertex);
210 }
211
onDrawInstanced(int instanceCount,int baseInstance,int vertexCount,int baseVertex)212 void GrDawnOpsRenderPass::onDrawInstanced(int instanceCount, int baseInstance,
213 int vertexCount, int baseVertex) {
214 fPassEncoder.Draw(vertexCount, instanceCount, baseVertex, baseInstance);
215 fGpu->stats()->incNumDraws();
216 }
217
onDrawIndexed(int indexCount,int baseIndex,uint16_t minIndexValue,uint16_t maxIndexValue,int baseVertex)218 void GrDawnOpsRenderPass::onDrawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue,
219 uint16_t maxIndexValue, int baseVertex) {
220 this->onDrawIndexedInstanced(indexCount, baseIndex, 1, 0, baseVertex);
221 }
222
onDrawIndexedInstanced(int indexCount,int baseIndex,int instanceCount,int baseInstance,int baseVertex)223 void GrDawnOpsRenderPass::onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
224 int baseInstance, int baseVertex) {
225 fPassEncoder.DrawIndexed(indexCount, instanceCount, baseIndex, baseVertex, baseInstance);
226 fGpu->stats()->incNumDraws();
227 }
228