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