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