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