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