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/GrD3DPipelineState.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h"
11cb93a386Sopenharmony_ci#include "src/gpu/GrFragmentProcessor.h"
12cb93a386Sopenharmony_ci#include "src/gpu/GrGeometryProcessor.h"
13cb93a386Sopenharmony_ci#include "src/gpu/GrProgramInfo.h"
14cb93a386Sopenharmony_ci#include "src/gpu/GrStencilSettings.h"
15cb93a386Sopenharmony_ci#include "src/gpu/GrXferProcessor.h"
16cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DBuffer.h"
17cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DGpu.h"
18cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DPipeline.h"
19cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DRootSignature.h"
20cb93a386Sopenharmony_ci#include "src/gpu/d3d/GrD3DTexture.h"
21cb93a386Sopenharmony_ci#include "src/gpu/effects/GrTextureEffect.h"
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ciGrD3DPipelineState::GrD3DPipelineState(
24cb93a386Sopenharmony_ci        sk_sp<GrD3DPipeline> pipeline,
25cb93a386Sopenharmony_ci        sk_sp<GrD3DRootSignature> rootSignature,
26cb93a386Sopenharmony_ci        const GrGLSLBuiltinUniformHandles& builtinUniformHandles,
27cb93a386Sopenharmony_ci        const UniformInfoArray& uniforms,
28cb93a386Sopenharmony_ci        uint32_t uniformSize,
29cb93a386Sopenharmony_ci        uint32_t numSamplers,
30cb93a386Sopenharmony_ci        std::unique_ptr<GrGeometryProcessor::ProgramImpl> gpImpl,
31cb93a386Sopenharmony_ci        std::unique_ptr<GrXferProcessor::ProgramImpl> xpImpl,
32cb93a386Sopenharmony_ci        std::vector<std::unique_ptr<GrFragmentProcessor::ProgramImpl>> fpImpls,
33cb93a386Sopenharmony_ci        size_t vertexStride,
34cb93a386Sopenharmony_ci        size_t instanceStride)
35cb93a386Sopenharmony_ci        : fPipeline(std::move(pipeline))
36cb93a386Sopenharmony_ci        , fRootSignature(std::move(rootSignature))
37cb93a386Sopenharmony_ci        , fBuiltinUniformHandles(builtinUniformHandles)
38cb93a386Sopenharmony_ci        , fGPImpl(std::move(gpImpl))
39cb93a386Sopenharmony_ci        , fXPImpl(std::move(xpImpl))
40cb93a386Sopenharmony_ci        , fFPImpls(std::move(fpImpls))
41cb93a386Sopenharmony_ci        , fDataManager(uniforms, uniformSize)
42cb93a386Sopenharmony_ci        , fNumSamplers(numSamplers)
43cb93a386Sopenharmony_ci        , fVertexStride(vertexStride)
44cb93a386Sopenharmony_ci        , fInstanceStride(instanceStride) {}
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_civoid GrD3DPipelineState::setAndBindConstants(GrD3DGpu* gpu,
47cb93a386Sopenharmony_ci                                             const GrRenderTarget* renderTarget,
48cb93a386Sopenharmony_ci                                             const GrProgramInfo& programInfo) {
49cb93a386Sopenharmony_ci    this->setRenderTargetState(renderTarget, programInfo.origin());
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ci    fGPImpl->setData(fDataManager, *gpu->caps()->shaderCaps(), programInfo.geomProc());
52cb93a386Sopenharmony_ci
53cb93a386Sopenharmony_ci    for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) {
54cb93a386Sopenharmony_ci        const auto& fp = programInfo.pipeline().getFragmentProcessor(i);
55cb93a386Sopenharmony_ci        fp.visitWithImpls([&](const GrFragmentProcessor& fp,
56cb93a386Sopenharmony_ci                              GrFragmentProcessor::ProgramImpl& impl) {
57cb93a386Sopenharmony_ci            impl.setData(fDataManager, fp);
58cb93a386Sopenharmony_ci        }, *fFPImpls[i]);
59cb93a386Sopenharmony_ci    }
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci    programInfo.pipeline().setDstTextureUniforms(fDataManager, &fBuiltinUniformHandles);
62cb93a386Sopenharmony_ci    fXPImpl->setData(fDataManager, programInfo.pipeline().getXferProcessor());
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ci    D3D12_GPU_VIRTUAL_ADDRESS constantsAddress = fDataManager.uploadConstants(gpu);
65cb93a386Sopenharmony_ci    gpu->currentCommandList()->setGraphicsRootConstantBufferView(
66cb93a386Sopenharmony_ci        (unsigned int)(GrD3DRootSignature::ParamIndex::kConstantBufferView),
67cb93a386Sopenharmony_ci        constantsAddress);
68cb93a386Sopenharmony_ci}
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_civoid GrD3DPipelineState::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin) {
71cb93a386Sopenharmony_ci    // Set RT adjustment and RT flip
72cb93a386Sopenharmony_ci    SkISize dimensions = rt->dimensions();
73cb93a386Sopenharmony_ci    SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid());
74cb93a386Sopenharmony_ci    if (fRenderTargetState.fRenderTargetOrigin != origin ||
75cb93a386Sopenharmony_ci        fRenderTargetState.fRenderTargetSize != dimensions) {
76cb93a386Sopenharmony_ci        fRenderTargetState.fRenderTargetSize = dimensions;
77cb93a386Sopenharmony_ci        fRenderTargetState.fRenderTargetOrigin = origin;
78cb93a386Sopenharmony_ci
79cb93a386Sopenharmony_ci        // The client will mark a swap buffer as kTopLeft when making a SkSurface because
80cb93a386Sopenharmony_ci        // D3D's framebuffer space has (0, 0) at the top left. This agrees with Skia's device
81cb93a386Sopenharmony_ci        // coords. However, in NDC (-1, -1) is the bottom left. So we flip when origin is kTopLeft.
82cb93a386Sopenharmony_ci        bool flip = (origin == kTopLeft_GrSurfaceOrigin);
83cb93a386Sopenharmony_ci        std::array<float, 4> v = SkSL::Compiler::GetRTAdjustVector(dimensions, flip);
84cb93a386Sopenharmony_ci        fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, v.data());
85cb93a386Sopenharmony_ci        if (fBuiltinUniformHandles.fRTFlipUni.isValid()) {
86cb93a386Sopenharmony_ci            // Note above that framebuffer space has origin top left. So we need !flip here.
87cb93a386Sopenharmony_ci            std::array<float, 2> d = SkSL::Compiler::GetRTFlipVector(rt->height(), !flip);
88cb93a386Sopenharmony_ci            fDataManager.set2fv(fBuiltinUniformHandles.fRTFlipUni, 1, d.data());
89cb93a386Sopenharmony_ci        }
90cb93a386Sopenharmony_ci    }
91cb93a386Sopenharmony_ci}
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_civoid GrD3DPipelineState::setAndBindTextures(GrD3DGpu* gpu,
94cb93a386Sopenharmony_ci                                            const GrGeometryProcessor& geomProc,
95cb93a386Sopenharmony_ci                                            const GrSurfaceProxy* const geomProcTextures[],
96cb93a386Sopenharmony_ci                                            const GrPipeline& pipeline) {
97cb93a386Sopenharmony_ci    SkASSERT(geomProcTextures || !geomProc.numTextureSamplers());
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci    std::vector<D3D12_CPU_DESCRIPTOR_HANDLE> shaderResourceViews(fNumSamplers);
100cb93a386Sopenharmony_ci    std::vector<D3D12_CPU_DESCRIPTOR_HANDLE> samplers(fNumSamplers);
101cb93a386Sopenharmony_ci    unsigned int currTextureBinding = 0;
102cb93a386Sopenharmony_ci
103cb93a386Sopenharmony_ci    for (int i = 0; i < geomProc.numTextureSamplers(); ++i) {
104cb93a386Sopenharmony_ci        SkASSERT(geomProcTextures[i]->asTextureProxy());
105cb93a386Sopenharmony_ci        const auto& sampler = geomProc.textureSampler(i);
106cb93a386Sopenharmony_ci        auto texture = static_cast<GrD3DTexture*>(geomProcTextures[i]->peekTexture());
107cb93a386Sopenharmony_ci        shaderResourceViews[currTextureBinding] = texture->shaderResourceView();
108cb93a386Sopenharmony_ci        samplers[currTextureBinding++] =
109cb93a386Sopenharmony_ci                gpu->resourceProvider().findOrCreateCompatibleSampler(sampler.samplerState());
110cb93a386Sopenharmony_ci        gpu->currentCommandList()->addSampledTextureRef(texture);
111cb93a386Sopenharmony_ci    }
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci    if (GrTexture* dstTexture = pipeline.peekDstTexture()) {
114cb93a386Sopenharmony_ci        auto texture = static_cast<GrD3DTexture*>(dstTexture);
115cb93a386Sopenharmony_ci        shaderResourceViews[currTextureBinding] = texture->shaderResourceView();
116cb93a386Sopenharmony_ci        samplers[currTextureBinding++] = gpu->resourceProvider().findOrCreateCompatibleSampler(
117cb93a386Sopenharmony_ci                                               GrSamplerState::Filter::kNearest);
118cb93a386Sopenharmony_ci        gpu->currentCommandList()->addSampledTextureRef(texture);
119cb93a386Sopenharmony_ci    }
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_ci    pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
122cb93a386Sopenharmony_ci        GrSamplerState samplerState = te.samplerState();
123cb93a386Sopenharmony_ci        auto* texture = static_cast<GrD3DTexture*>(te.texture());
124cb93a386Sopenharmony_ci        shaderResourceViews[currTextureBinding] = texture->shaderResourceView();
125cb93a386Sopenharmony_ci        samplers[currTextureBinding++] =
126cb93a386Sopenharmony_ci                gpu->resourceProvider().findOrCreateCompatibleSampler(samplerState);
127cb93a386Sopenharmony_ci        gpu->currentCommandList()->addSampledTextureRef(texture);
128cb93a386Sopenharmony_ci    });
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_ci    SkASSERT(fNumSamplers == currTextureBinding);
131cb93a386Sopenharmony_ci
132cb93a386Sopenharmony_ci    // fill in descriptor tables and bind to root signature
133cb93a386Sopenharmony_ci    if (fNumSamplers > 0) {
134cb93a386Sopenharmony_ci        // set up descriptor tables and bind heaps
135cb93a386Sopenharmony_ci        sk_sp<GrD3DDescriptorTable> srvTable =
136cb93a386Sopenharmony_ci                gpu->resourceProvider().findOrCreateShaderViewTable(shaderResourceViews);
137cb93a386Sopenharmony_ci        sk_sp<GrD3DDescriptorTable> samplerTable =
138cb93a386Sopenharmony_ci            gpu->resourceProvider().findOrCreateSamplerTable(samplers);
139cb93a386Sopenharmony_ci        gpu->currentCommandList()->setDescriptorHeaps(srvTable->heap(), samplerTable->heap());
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ci        // bind shader resource view table
142cb93a386Sopenharmony_ci        gpu->currentCommandList()->setGraphicsRootDescriptorTable(
143cb93a386Sopenharmony_ci                (unsigned int)GrD3DRootSignature::ParamIndex::kShaderViewDescriptorTable,
144cb93a386Sopenharmony_ci                srvTable->baseGpuDescriptor());
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_ci        // bind sampler table
147cb93a386Sopenharmony_ci        gpu->currentCommandList()->setGraphicsRootDescriptorTable(
148cb93a386Sopenharmony_ci                (unsigned int)GrD3DRootSignature::ParamIndex::kSamplerDescriptorTable,
149cb93a386Sopenharmony_ci                samplerTable->baseGpuDescriptor());
150cb93a386Sopenharmony_ci    }
151cb93a386Sopenharmony_ci}
152cb93a386Sopenharmony_ci
153cb93a386Sopenharmony_civoid GrD3DPipelineState::bindBuffers(GrD3DGpu* gpu, sk_sp<const GrBuffer> indexBuffer,
154cb93a386Sopenharmony_ci                                     sk_sp<const GrBuffer> instanceBuffer,
155cb93a386Sopenharmony_ci                                     sk_sp<const GrBuffer> vertexBuffer,
156cb93a386Sopenharmony_ci                                     GrD3DDirectCommandList* commandList) {
157cb93a386Sopenharmony_ci    // Here our vertex and instance inputs need to match the same 0-based bindings they were
158cb93a386Sopenharmony_ci    // assigned in the PipelineState. That is, vertex first (if any) followed by instance.
159cb93a386Sopenharmony_ci    if (vertexBuffer) {
160cb93a386Sopenharmony_ci        auto* d3dVertexBuffer = static_cast<const GrD3DBuffer*>(vertexBuffer.get());
161cb93a386Sopenharmony_ci        SkASSERT(!d3dVertexBuffer->isCpuBuffer());
162cb93a386Sopenharmony_ci        SkASSERT(!d3dVertexBuffer->isMapped());
163cb93a386Sopenharmony_ci        const_cast<GrD3DBuffer*>(d3dVertexBuffer)->setResourceState(
164cb93a386Sopenharmony_ci                gpu, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
165cb93a386Sopenharmony_ci    }
166cb93a386Sopenharmony_ci    if (instanceBuffer) {
167cb93a386Sopenharmony_ci        auto* d3dInstanceBuffer = static_cast<const GrD3DBuffer*>(instanceBuffer.get());
168cb93a386Sopenharmony_ci        SkASSERT(!d3dInstanceBuffer->isCpuBuffer());
169cb93a386Sopenharmony_ci        SkASSERT(!d3dInstanceBuffer->isMapped());
170cb93a386Sopenharmony_ci        const_cast<GrD3DBuffer*>(d3dInstanceBuffer)->setResourceState(
171cb93a386Sopenharmony_ci                gpu, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
172cb93a386Sopenharmony_ci    }
173cb93a386Sopenharmony_ci    commandList->setVertexBuffers(0, std::move(vertexBuffer), fVertexStride,
174cb93a386Sopenharmony_ci                                  std::move(instanceBuffer), fInstanceStride);
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ci    if (auto* d3dIndexBuffer = static_cast<const GrD3DBuffer*>(indexBuffer.get())) {
177cb93a386Sopenharmony_ci        SkASSERT(!d3dIndexBuffer->isCpuBuffer());
178cb93a386Sopenharmony_ci        SkASSERT(!d3dIndexBuffer->isMapped());
179cb93a386Sopenharmony_ci        const_cast<GrD3DBuffer*>(d3dIndexBuffer)->setResourceState(
180cb93a386Sopenharmony_ci                gpu, D3D12_RESOURCE_STATE_INDEX_BUFFER);
181cb93a386Sopenharmony_ci        commandList->setIndexBuffer(std::move(indexBuffer));
182cb93a386Sopenharmony_ci    }
183cb93a386Sopenharmony_ci}
184