• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 Google LLC
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/d3d/GrD3DOpsRenderPass.h"
9 
10 #include "src/gpu/ganesh/GrBackendUtils.h"
11 #include "src/gpu/ganesh/GrOpFlushState.h"
12 #include "src/gpu/ganesh/GrProgramDesc.h"
13 #include "src/gpu/ganesh/GrRenderTarget.h"
14 #include "src/gpu/ganesh/GrStencilSettings.h"
15 #include "src/gpu/ganesh/d3d/GrD3DBuffer.h"
16 #include "src/gpu/ganesh/d3d/GrD3DCommandSignature.h"
17 #include "src/gpu/ganesh/d3d/GrD3DGpu.h"
18 #include "src/gpu/ganesh/d3d/GrD3DPipelineState.h"
19 #include "src/gpu/ganesh/d3d/GrD3DPipelineStateBuilder.h"
20 #include "src/gpu/ganesh/d3d/GrD3DRenderTarget.h"
21 #include "src/gpu/ganesh/d3d/GrD3DTexture.h"
22 #include "src/gpu/ganesh/effects/GrTextureEffect.h"
23 
24 #ifdef SK_DEBUG
25 #include "include/gpu/GrDirectContext.h"
26 #include "src/gpu/ganesh/GrDirectContextPriv.h"
27 #endif
28 
GrD3DOpsRenderPass(GrD3DGpu * gpu)29 GrD3DOpsRenderPass::GrD3DOpsRenderPass(GrD3DGpu* gpu) : fGpu(gpu) {}
30 
set(GrRenderTarget * rt,GrSurfaceOrigin origin,const SkIRect & bounds,const GrOpsRenderPass::LoadAndStoreInfo & colorInfo,const GrOpsRenderPass::StencilLoadAndStoreInfo & stencilInfo,const SkTArray<GrSurfaceProxy *,true> & sampledProxies)31 bool GrD3DOpsRenderPass::set(GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds,
32                              const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
33                              const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
34                              const SkTArray<GrSurfaceProxy*, true>& sampledProxies) {
35     SkASSERT(!fRenderTarget);
36     SkASSERT(fGpu == rt->getContext()->priv().getGpu());
37 
38     this->INHERITED::set(rt, origin);
39 
40     fBounds = bounds;
41 
42     fColorLoadOp = colorInfo.fLoadOp;
43     fClearColor = colorInfo.fClearColor;
44     fStencilLoadOp = stencilInfo.fLoadOp;
45 
46     // TODO
47 
48     return true;
49 }
50 
~GrD3DOpsRenderPass()51 GrD3DOpsRenderPass::~GrD3DOpsRenderPass() {}
52 
gpu()53 GrGpu* GrD3DOpsRenderPass::gpu() { return fGpu; }
54 
onBegin()55 void GrD3DOpsRenderPass::onBegin() {
56     GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(fRenderTarget);
57     if (d3dRT->numSamples() > 1) {
58         d3dRT->msaaTextureResource()->setResourceState(fGpu, D3D12_RESOURCE_STATE_RENDER_TARGET);
59     } else {
60         d3dRT->setResourceState(fGpu, D3D12_RESOURCE_STATE_RENDER_TARGET);
61     }
62     fGpu->currentCommandList()->setRenderTarget(d3dRT);
63 
64     if (GrLoadOp::kClear == fColorLoadOp) {
65         // Passing in nullptr for the rect clears the entire d3d RT. Is this correct? Does the load
66         // op respect the logical bounds of a RT?
67         fGpu->currentCommandList()->clearRenderTargetView(d3dRT, fClearColor, nullptr);
68     }
69 
70     if (auto stencil = d3dRT->getStencilAttachment()) {
71         GrD3DAttachment* d3dStencil = static_cast<GrD3DAttachment*>(stencil);
72         d3dStencil->setResourceState(fGpu, D3D12_RESOURCE_STATE_DEPTH_WRITE);
73         if (fStencilLoadOp == GrLoadOp::kClear) {
74             fGpu->currentCommandList()->clearDepthStencilView(d3dStencil, 0, nullptr);
75         }
76     }
77 }
78 
set_stencil_ref(GrD3DGpu * gpu,const GrProgramInfo & info)79 void set_stencil_ref(GrD3DGpu* gpu, const GrProgramInfo& info) {
80     GrStencilSettings stencilSettings = info.nonGLStencilSettings();
81     if (!stencilSettings.isDisabled()) {
82         unsigned int stencilRef = 0;
83         if (stencilSettings.isTwoSided()) {
84             SkASSERT(stencilSettings.postOriginCCWFace(info.origin()).fRef ==
85                      stencilSettings.postOriginCWFace(info.origin()).fRef);
86             stencilRef = stencilSettings.postOriginCCWFace(info.origin()).fRef;
87         } else {
88             stencilRef = stencilSettings.singleSidedFace().fRef;
89         }
90         gpu->currentCommandList()->setStencilRef(stencilRef);
91     }
92 }
93 
set_blend_factor(GrD3DGpu * gpu,const GrProgramInfo & info)94 void set_blend_factor(GrD3DGpu* gpu, const GrProgramInfo& info) {
95     const GrXferProcessor& xferProcessor = info.pipeline().getXferProcessor();
96     const skgpu::Swizzle& swizzle = info.pipeline().writeSwizzle();
97     const skgpu::BlendInfo& blendInfo = xferProcessor.getBlendInfo();
98     skgpu::BlendCoeff srcCoeff = blendInfo.fSrcBlend;
99     skgpu::BlendCoeff dstCoeff = blendInfo.fDstBlend;
100     float floatColors[4];
101     if (skgpu::BlendCoeffRefsConstant(srcCoeff) || skgpu::BlendCoeffRefsConstant(dstCoeff)) {
102         // Swizzle the blend to match what the shader will output.
103         SkPMColor4f blendConst = swizzle.applyTo(blendInfo.fBlendConstant);
104         floatColors[0] = blendConst.fR;
105         floatColors[1] = blendConst.fG;
106         floatColors[2] = blendConst.fB;
107         floatColors[3] = blendConst.fA;
108     } else {
109         memset(floatColors, 0, 4 * sizeof(float));
110     }
111     gpu->currentCommandList()->setBlendFactor(floatColors);
112 }
113 
set_primitive_topology(GrD3DGpu * gpu,const GrProgramInfo & info)114 void set_primitive_topology(GrD3DGpu* gpu, const GrProgramInfo& info) {
115     D3D12_PRIMITIVE_TOPOLOGY topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
116     switch (info.primitiveType()) {
117         case GrPrimitiveType::kTriangles:
118             topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
119             break;
120         case GrPrimitiveType::kTriangleStrip:
121             topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
122             break;
123         case GrPrimitiveType::kPoints:
124             topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
125             break;
126         case GrPrimitiveType::kLines:
127             topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
128             break;
129         case GrPrimitiveType::kLineStrip:
130             topology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
131             break;
132         default:
133             SkUNREACHABLE;
134     }
135     gpu->currentCommandList()->setPrimitiveTopology(topology);
136 }
137 
set_scissor_rects(GrD3DGpu * gpu,const GrRenderTarget * renderTarget,GrSurfaceOrigin rtOrigin,const SkIRect & scissorRect)138 void set_scissor_rects(GrD3DGpu* gpu, const GrRenderTarget* renderTarget, GrSurfaceOrigin rtOrigin,
139                        const SkIRect& scissorRect) {
140     SkASSERT(scissorRect.isEmpty() ||
141              SkIRect::MakeWH(renderTarget->width(), renderTarget->height()).contains(scissorRect));
142 
143     D3D12_RECT scissor;
144     scissor.left = scissorRect.fLeft;
145     scissor.right = scissorRect.fRight;
146     if (kTopLeft_GrSurfaceOrigin == rtOrigin) {
147         scissor.top = scissorRect.fTop;
148     } else {
149         SkASSERT(kBottomLeft_GrSurfaceOrigin == rtOrigin);
150         scissor.top = renderTarget->height() - scissorRect.fBottom;
151     }
152     scissor.bottom = scissor.top + scissorRect.height();
153 
154     SkASSERT(scissor.left >= 0);
155     SkASSERT(scissor.top >= 0);
156     gpu->currentCommandList()->setScissorRects(1, &scissor);
157 }
158 
set_viewport(GrD3DGpu * gpu,const GrRenderTarget * renderTarget)159 void set_viewport(GrD3DGpu* gpu, const GrRenderTarget* renderTarget) {
160     D3D12_VIEWPORT viewport;
161     viewport.TopLeftX = 0.0f;
162     viewport.TopLeftY = 0.0f;
163     viewport.Width = SkIntToScalar(renderTarget->width());
164     viewport.Height = SkIntToScalar(renderTarget->height());
165     viewport.MinDepth = 0.0f;
166     viewport.MaxDepth = 1.0f;
167     gpu->currentCommandList()->setViewports(1, &viewport);
168 }
169 
onBindPipeline(const GrProgramInfo & info,const SkRect & drawBounds)170 bool GrD3DOpsRenderPass::onBindPipeline(const GrProgramInfo& info, const SkRect& drawBounds) {
171     SkRect rtRect = SkRect::Make(fBounds);
172     if (rtRect.intersect(drawBounds)) {
173         rtRect.roundOut(&fCurrentPipelineBounds);
174     } else {
175         fCurrentPipelineBounds.setEmpty();
176     }
177 
178     GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(fRenderTarget);
179     fCurrentPipelineState =
180             fGpu->resourceProvider().findOrCreateCompatiblePipelineState(d3dRT, info);
181     if (!fCurrentPipelineState) {
182         return false;
183     }
184 
185     fGpu->currentCommandList()->setGraphicsRootSignature(fCurrentPipelineState->rootSignature());
186     fGpu->currentCommandList()->setPipelineState(fCurrentPipelineState->pipeline());
187     fCurrentPipelineState->setAndBindConstants(fGpu, fRenderTarget, info);
188 
189     set_stencil_ref(fGpu, info);
190     set_blend_factor(fGpu, info);
191     set_primitive_topology(fGpu, info);
192     if (!info.pipeline().isScissorTestEnabled()) {
193         // "Disable" scissor by setting it to the full pipeline bounds.
194         set_scissor_rects(fGpu, fRenderTarget, fOrigin, fCurrentPipelineBounds);
195     }
196     set_viewport(fGpu, fRenderTarget);
197 
198     return true;
199 }
200 
onSetScissorRect(const SkIRect & scissor)201 void GrD3DOpsRenderPass::onSetScissorRect(const SkIRect& scissor) {
202     SkIRect combinedScissorRect;
203     if (!combinedScissorRect.intersect(fCurrentPipelineBounds, scissor)) {
204         combinedScissorRect = SkIRect::MakeEmpty();
205     }
206 
207     set_scissor_rects(fGpu, fRenderTarget, fOrigin, combinedScissorRect);
208 }
209 
update_resource_state(GrTexture * tex,GrRenderTarget * rt,GrD3DGpu * gpu)210 void update_resource_state(GrTexture* tex, GrRenderTarget* rt, GrD3DGpu* gpu) {
211     SkASSERT(!tex->isProtected() || (rt->isProtected() && gpu->protectedContext()));
212     GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(tex);
213     SkASSERT(d3dTex);
214     d3dTex->setResourceState(gpu, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
215 }
216 
onBindTextures(const GrGeometryProcessor & geomProc,const GrSurfaceProxy * const geomProcTextures[],const GrPipeline & pipeline)217 bool GrD3DOpsRenderPass::onBindTextures(const GrGeometryProcessor& geomProc,
218                                         const GrSurfaceProxy* const geomProcTextures[],
219                                         const GrPipeline& pipeline) {
220     SkASSERT(fCurrentPipelineState);
221 
222     // update textures to sampled resource state
223     for (int i = 0; i < geomProc.numTextureSamplers(); ++i) {
224         update_resource_state(geomProcTextures[i]->peekTexture(), fRenderTarget, fGpu);
225     }
226 
227     pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
228         update_resource_state(te.texture(), fRenderTarget, fGpu);
229     });
230 
231     if (GrTexture* dstTexture = pipeline.peekDstTexture()) {
232         update_resource_state(dstTexture, fRenderTarget, fGpu);
233     }
234 
235     // TODO: possibly check for success once we start binding properly
236     fCurrentPipelineState->setAndBindTextures(fGpu, geomProc, geomProcTextures, pipeline);
237 
238     return true;
239 }
240 
onBindBuffers(sk_sp<const GrBuffer> indexBuffer,sk_sp<const GrBuffer> instanceBuffer,sk_sp<const GrBuffer> vertexBuffer,GrPrimitiveRestart primRestart)241 void GrD3DOpsRenderPass::onBindBuffers(sk_sp<const GrBuffer> indexBuffer,
242                                        sk_sp<const GrBuffer> instanceBuffer,
243                                        sk_sp<const GrBuffer> vertexBuffer,
244                                        GrPrimitiveRestart primRestart) {
245     SkASSERT(GrPrimitiveRestart::kNo == primRestart);
246     SkASSERT(fCurrentPipelineState);
247     SkASSERT(!fGpu->caps()->usePrimitiveRestart());  // Ignore primitiveRestart parameter.
248 
249     GrD3DDirectCommandList* currCmdList = fGpu->currentCommandList();
250     SkASSERT(currCmdList);
251 
252     fCurrentPipelineState->bindBuffers(fGpu, std::move(indexBuffer), std::move(instanceBuffer),
253                                        std::move(vertexBuffer), currCmdList);
254 }
255 
onDrawInstanced(int instanceCount,int baseInstance,int vertexCount,int baseVertex)256 void GrD3DOpsRenderPass::onDrawInstanced(int instanceCount, int baseInstance, int vertexCount,
257                                             int baseVertex) {
258     SkASSERT(fCurrentPipelineState);
259     fGpu->currentCommandList()->drawInstanced(vertexCount, instanceCount, baseVertex, baseInstance);
260     fGpu->stats()->incNumDraws();
261 }
262 
onDrawIndexedInstanced(int indexCount,int baseIndex,int instanceCount,int baseInstance,int baseVertex)263 void GrD3DOpsRenderPass::onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
264                                                 int baseInstance, int baseVertex) {
265     SkASSERT(fCurrentPipelineState);
266     fGpu->currentCommandList()->drawIndexedInstanced(indexCount, instanceCount, baseIndex,
267                                                      baseVertex, baseInstance);
268     fGpu->stats()->incNumDraws();
269 }
270 
onDrawIndirect(const GrBuffer * buffer,size_t offset,int drawCount)271 void GrD3DOpsRenderPass::onDrawIndirect(const GrBuffer* buffer, size_t offset, int drawCount) {
272     constexpr unsigned int kSlot = 0;
273     sk_sp<GrD3DCommandSignature> cmdSig = fGpu->resourceProvider().findOrCreateCommandSignature(
274             GrD3DCommandSignature::ForIndexed::kNo, kSlot);
275     fGpu->currentCommandList()->executeIndirect(cmdSig, drawCount,
276                                                 static_cast<const GrD3DBuffer*>(buffer), offset);
277     fGpu->stats()->incNumDraws();
278 }
279 
onDrawIndexedIndirect(const GrBuffer * buffer,size_t offset,int drawCount)280 void GrD3DOpsRenderPass::onDrawIndexedIndirect(const GrBuffer* buffer, size_t offset,
281                                                int drawCount) {
282     constexpr unsigned int kSlot = 0;
283     sk_sp<GrD3DCommandSignature> cmdSig = fGpu->resourceProvider().findOrCreateCommandSignature(
284             GrD3DCommandSignature::ForIndexed::kYes, kSlot);
285     fGpu->currentCommandList()->executeIndirect(cmdSig, drawCount,
286                                                 static_cast<const GrD3DBuffer*>(buffer), offset);
287     fGpu->stats()->incNumDraws();
288 }
289 
290 
scissor_to_d3d_clear_rect(const GrScissorState & scissor,const GrSurface * surface,GrSurfaceOrigin origin)291 static D3D12_RECT scissor_to_d3d_clear_rect(const GrScissorState& scissor,
292                                             const GrSurface* surface,
293                                             GrSurfaceOrigin origin) {
294     D3D12_RECT clearRect;
295     // Flip rect if necessary
296     SkIRect d3dRect;
297     if (!scissor.enabled()) {
298         d3dRect.setXYWH(0, 0, surface->width(), surface->height());
299     } else if (kBottomLeft_GrSurfaceOrigin != origin) {
300         d3dRect = scissor.rect();
301     } else {
302         d3dRect.setLTRB(scissor.rect().fLeft, surface->height() - scissor.rect().fBottom,
303                         scissor.rect().fRight, surface->height() - scissor.rect().fTop);
304     }
305     clearRect.left = d3dRect.fLeft;
306     clearRect.right = d3dRect.fRight;
307     clearRect.top = d3dRect.fTop;
308     clearRect.bottom = d3dRect.fBottom;
309     return clearRect;
310 }
311 
onClear(const GrScissorState & scissor,std::array<float,4> color)312 void GrD3DOpsRenderPass::onClear(const GrScissorState& scissor, std::array<float, 4> color) {
313     D3D12_RECT clearRect = scissor_to_d3d_clear_rect(scissor, fRenderTarget, fOrigin);
314     auto d3dRT = static_cast<GrD3DRenderTarget*>(fRenderTarget);
315     SkASSERT(d3dRT->grD3DResourceState()->getResourceState() == D3D12_RESOURCE_STATE_RENDER_TARGET);
316     fGpu->currentCommandList()->clearRenderTargetView(d3dRT, color, &clearRect);
317 }
318 
onClearStencilClip(const GrScissorState & scissor,bool insideStencilMask)319 void GrD3DOpsRenderPass::onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) {
320     GrAttachment* sb = fRenderTarget->getStencilAttachment();
321     // this should only be called internally when we know we have a
322     // stencil buffer.
323     SkASSERT(sb);
324     int stencilBitCount = GrBackendFormatStencilBits(sb->backendFormat());
325 
326     // The contract with the callers does not guarantee that we preserve all bits in the stencil
327     // during this clear. Thus we will clear the entire stencil to the desired value.
328 
329     uint8_t stencilColor = 0;
330     if (insideStencilMask) {
331         stencilColor = (1 << (stencilBitCount - 1));
332     }
333 
334     D3D12_RECT clearRect = scissor_to_d3d_clear_rect(scissor, fRenderTarget, fOrigin);
335 
336     auto d3dStencil = static_cast<GrD3DAttachment*>(sb);
337     fGpu->currentCommandList()->clearDepthStencilView(d3dStencil, stencilColor, &clearRect);
338 }
339 
inlineUpload(GrOpFlushState * state,GrDeferredTextureUploadFn & upload)340 void GrD3DOpsRenderPass::inlineUpload(GrOpFlushState* state, GrDeferredTextureUploadFn& upload) {
341     // If we ever start using copy command lists for doing uploads, then we'll need to make sure
342     // we submit our main command list before doing the copy here and then start a new main command
343     // list.
344 
345     fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds);
346 
347     // We pass in true here to signal that after the upload we need to set the upload texture's
348     // resource state back to D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE.
349     state->doUpload(upload, true);
350 }
351 
submit()352 void GrD3DOpsRenderPass::submit() {
353     if (!fRenderTarget) {
354         return;
355     }
356 
357     // We don't use render passes in d3d, so there is nothing to submit here as all commands have
358     // already been recorded on the main command list. If in the future we start to use render
359     // passes on d3d12 devices that support them (most likely ARM devices), then we
360     // will submit them here.
361     fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds);
362 }
363