1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc.
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/vk/GrVkPipelineState.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "src/core/SkMipmap.h"
11cb93a386Sopenharmony_ci#include "src/gpu/GrFragmentProcessor.h"
12cb93a386Sopenharmony_ci#include "src/gpu/GrGeometryProcessor.h"
13cb93a386Sopenharmony_ci#include "src/gpu/GrPipeline.h"
14cb93a386Sopenharmony_ci#include "src/gpu/GrRenderTarget.h"
15cb93a386Sopenharmony_ci#include "src/gpu/GrTexture.h"
16cb93a386Sopenharmony_ci#include "src/gpu/GrXferProcessor.h"
17cb93a386Sopenharmony_ci#include "src/gpu/effects/GrTextureEffect.h"
18cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkBuffer.h"
19cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkCommandBuffer.h"
20cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkDescriptorPool.h"
21cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkDescriptorSet.h"
22cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkGpu.h"
23cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkImageView.h"
24cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkMemory.h"
25cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkPipeline.h"
26cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkRenderTarget.h"
27cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkSampler.h"
28cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkTexture.h"
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ciGrVkPipelineState::GrVkPipelineState(
31cb93a386Sopenharmony_ci        GrVkGpu* gpu,
32cb93a386Sopenharmony_ci        sk_sp<const GrVkPipeline> pipeline,
33cb93a386Sopenharmony_ci        const GrVkDescriptorSetManager::Handle& samplerDSHandle,
34cb93a386Sopenharmony_ci        const GrGLSLBuiltinUniformHandles& builtinUniformHandles,
35cb93a386Sopenharmony_ci        const UniformInfoArray& uniforms,
36cb93a386Sopenharmony_ci        uint32_t uniformSize,
37cb93a386Sopenharmony_ci        bool usePushConstants,
38cb93a386Sopenharmony_ci        const UniformInfoArray& samplers,
39cb93a386Sopenharmony_ci        std::unique_ptr<GrGeometryProcessor::ProgramImpl> gpImpl,
40cb93a386Sopenharmony_ci        std::unique_ptr<GrXferProcessor::ProgramImpl> xpImpl,
41cb93a386Sopenharmony_ci        std::vector<std::unique_ptr<GrFragmentProcessor::ProgramImpl>> fpImpls)
42cb93a386Sopenharmony_ci        : fPipeline(std::move(pipeline))
43cb93a386Sopenharmony_ci        , fSamplerDSHandle(samplerDSHandle)
44cb93a386Sopenharmony_ci        , fBuiltinUniformHandles(builtinUniformHandles)
45cb93a386Sopenharmony_ci        , fGPImpl(std::move(gpImpl))
46cb93a386Sopenharmony_ci        , fXPImpl(std::move(xpImpl))
47cb93a386Sopenharmony_ci        , fFPImpls(std::move(fpImpls))
48cb93a386Sopenharmony_ci        , fDataManager(uniforms, uniformSize, usePushConstants) {
49cb93a386Sopenharmony_ci    fNumSamplers = samplers.count();
50cb93a386Sopenharmony_ci    for (const auto& sampler : samplers.items()) {
51cb93a386Sopenharmony_ci        // We store the immutable samplers here and take a ref on the sampler. Once we switch to
52cb93a386Sopenharmony_ci        // using sk_sps here we should just move the immutable samplers to save the extra ref/unref.
53cb93a386Sopenharmony_ci        if (sampler.fImmutableSampler) {
54cb93a386Sopenharmony_ci            sampler.fImmutableSampler->ref();
55cb93a386Sopenharmony_ci        }
56cb93a386Sopenharmony_ci        fImmutableSamplers.push_back(sampler.fImmutableSampler);
57cb93a386Sopenharmony_ci    }
58cb93a386Sopenharmony_ci}
59cb93a386Sopenharmony_ci
60cb93a386Sopenharmony_ciGrVkPipelineState::~GrVkPipelineState() {
61cb93a386Sopenharmony_ci    // Must have freed all GPU resources before this is destroyed
62cb93a386Sopenharmony_ci    SkASSERT(!fPipeline);
63cb93a386Sopenharmony_ci}
64cb93a386Sopenharmony_ci
65cb93a386Sopenharmony_civoid GrVkPipelineState::freeGPUResources(GrVkGpu* gpu) {
66cb93a386Sopenharmony_ci    fPipeline.reset();
67cb93a386Sopenharmony_ci    fDataManager.releaseData();
68cb93a386Sopenharmony_ci    for (int i = 0; i < fImmutableSamplers.count(); ++i) {
69cb93a386Sopenharmony_ci        if (fImmutableSamplers[i]) {
70cb93a386Sopenharmony_ci            fImmutableSamplers[i]->unref();
71cb93a386Sopenharmony_ci            fImmutableSamplers[i] = nullptr;
72cb93a386Sopenharmony_ci        }
73cb93a386Sopenharmony_ci    }
74cb93a386Sopenharmony_ci}
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_cibool GrVkPipelineState::setAndBindUniforms(GrVkGpu* gpu,
77cb93a386Sopenharmony_ci                                           SkISize colorAttachmentDimensions,
78cb93a386Sopenharmony_ci                                           const GrProgramInfo& programInfo,
79cb93a386Sopenharmony_ci                                           GrVkCommandBuffer* commandBuffer) {
80cb93a386Sopenharmony_ci    this->setRenderTargetState(colorAttachmentDimensions, programInfo.origin());
81cb93a386Sopenharmony_ci
82cb93a386Sopenharmony_ci    fGPImpl->setData(fDataManager, *gpu->caps()->shaderCaps(), programInfo.geomProc());
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_ci    for (int i = 0; i < programInfo.pipeline().numFragmentProcessors(); ++i) {
85cb93a386Sopenharmony_ci        const auto& fp = programInfo.pipeline().getFragmentProcessor(i);
86cb93a386Sopenharmony_ci        fp.visitWithImpls([&](const GrFragmentProcessor& fp,
87cb93a386Sopenharmony_ci                              GrFragmentProcessor::ProgramImpl& impl) {
88cb93a386Sopenharmony_ci            impl.setData(fDataManager, fp);
89cb93a386Sopenharmony_ci        }, *fFPImpls[i]);
90cb93a386Sopenharmony_ci    }
91cb93a386Sopenharmony_ci
92cb93a386Sopenharmony_ci    programInfo.pipeline().setDstTextureUniforms(fDataManager, &fBuiltinUniformHandles);
93cb93a386Sopenharmony_ci    fXPImpl->setData(fDataManager, programInfo.pipeline().getXferProcessor());
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_ci    // Upload uniform data and bind descriptor set.
96cb93a386Sopenharmony_ci    auto [uniformBuffer, success] = fDataManager.uploadUniforms(gpu, fPipeline->layout(),
97cb93a386Sopenharmony_ci                                                                commandBuffer);
98cb93a386Sopenharmony_ci    if (!success) {
99cb93a386Sopenharmony_ci        return false;
100cb93a386Sopenharmony_ci    }
101cb93a386Sopenharmony_ci    if (uniformBuffer) {
102cb93a386Sopenharmony_ci        const GrVkBuffer* vkBuffer = static_cast<GrVkBuffer*>(uniformBuffer.get());
103cb93a386Sopenharmony_ci        static const int kUniformDSIdx = GrVkUniformHandler::kUniformBufferDescSet;
104cb93a386Sopenharmony_ci        commandBuffer->bindDescriptorSets(gpu, fPipeline->layout(), kUniformDSIdx, /*setCount=*/1,
105cb93a386Sopenharmony_ci                                          vkBuffer->uniformDescriptorSet(),
106cb93a386Sopenharmony_ci                                          /*dynamicOffsetCount=*/0, /*dynamicOffsets=*/nullptr);
107cb93a386Sopenharmony_ci        commandBuffer->addGrBuffer(std::move(uniformBuffer));
108cb93a386Sopenharmony_ci    }
109cb93a386Sopenharmony_ci    return true;
110cb93a386Sopenharmony_ci}
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_cibool GrVkPipelineState::setAndBindTextures(GrVkGpu* gpu,
113cb93a386Sopenharmony_ci                                           const GrGeometryProcessor& geomProc,
114cb93a386Sopenharmony_ci                                           const GrPipeline& pipeline,
115cb93a386Sopenharmony_ci                                           const GrSurfaceProxy* const geomProcTextures[],
116cb93a386Sopenharmony_ci                                           GrVkCommandBuffer* commandBuffer) {
117cb93a386Sopenharmony_ci    SkASSERT(geomProcTextures || !geomProc.numTextureSamplers());
118cb93a386Sopenharmony_ci    if (!fNumSamplers) {
119cb93a386Sopenharmony_ci        return true;
120cb93a386Sopenharmony_ci    }
121cb93a386Sopenharmony_ci    struct SamplerBindings {
122cb93a386Sopenharmony_ci        GrSamplerState fState;
123cb93a386Sopenharmony_ci        GrVkTexture* fTexture;
124cb93a386Sopenharmony_ci    };
125cb93a386Sopenharmony_ci    SkAutoSTArray<8, SamplerBindings> samplerBindings(fNumSamplers);
126cb93a386Sopenharmony_ci    int currTextureBinding = 0;
127cb93a386Sopenharmony_ci
128cb93a386Sopenharmony_ci    for (int i = 0; i < geomProc.numTextureSamplers(); ++i) {
129cb93a386Sopenharmony_ci        SkASSERT(geomProcTextures[i]->asTextureProxy());
130cb93a386Sopenharmony_ci        const auto& sampler = geomProc.textureSampler(i);
131cb93a386Sopenharmony_ci        auto texture = static_cast<GrVkTexture*>(geomProcTextures[i]->peekTexture());
132cb93a386Sopenharmony_ci        samplerBindings[currTextureBinding++] = {sampler.samplerState(), texture};
133cb93a386Sopenharmony_ci    }
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci
136cb93a386Sopenharmony_ci    if (GrTexture* dstTexture = pipeline.peekDstTexture()) {
137cb93a386Sopenharmony_ci        samplerBindings[currTextureBinding++] = {GrSamplerState::Filter::kNearest,
138cb93a386Sopenharmony_ci                                                 static_cast<GrVkTexture*>(dstTexture)};
139cb93a386Sopenharmony_ci    }
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ci    pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
142cb93a386Sopenharmony_ci        GrSamplerState samplerState = te.samplerState();
143cb93a386Sopenharmony_ci        auto* texture = static_cast<GrVkTexture*>(te.texture());
144cb93a386Sopenharmony_ci        samplerBindings[currTextureBinding++] = {samplerState, texture};
145cb93a386Sopenharmony_ci    });
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_ci    // Get new descriptor set
148cb93a386Sopenharmony_ci    SkASSERT(fNumSamplers == currTextureBinding);
149cb93a386Sopenharmony_ci    static const int kSamplerDSIdx = GrVkUniformHandler::kSamplerDescSet;
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_ci    if (fNumSamplers == 1) {
152cb93a386Sopenharmony_ci        auto texture = samplerBindings[0].fTexture;
153cb93a386Sopenharmony_ci        auto texAttachment = texture->textureImage();
154cb93a386Sopenharmony_ci        const auto& samplerState = samplerBindings[0].fState;
155cb93a386Sopenharmony_ci        const GrVkDescriptorSet* descriptorSet = texture->cachedSingleDescSet(samplerState);
156cb93a386Sopenharmony_ci        if (descriptorSet) {
157cb93a386Sopenharmony_ci            commandBuffer->addGrSurface(sk_ref_sp<const GrSurface>(texture));
158cb93a386Sopenharmony_ci            commandBuffer->addResource(texAttachment->textureView());
159cb93a386Sopenharmony_ci            commandBuffer->addResource(texAttachment->resource());
160cb93a386Sopenharmony_ci            commandBuffer->addRecycledResource(descriptorSet);
161cb93a386Sopenharmony_ci            commandBuffer->bindDescriptorSets(gpu, fPipeline->layout(), kSamplerDSIdx,
162cb93a386Sopenharmony_ci                                              /*setCount=*/1, descriptorSet->descriptorSet(),
163cb93a386Sopenharmony_ci                                              /*dynamicOffsetCount=*/0,
164cb93a386Sopenharmony_ci                                              /*dynamicOffsets=*/nullptr);
165cb93a386Sopenharmony_ci            return true;
166cb93a386Sopenharmony_ci        }
167cb93a386Sopenharmony_ci    }
168cb93a386Sopenharmony_ci
169cb93a386Sopenharmony_ci    const GrVkDescriptorSet* descriptorSet =
170cb93a386Sopenharmony_ci            gpu->resourceProvider().getSamplerDescriptorSet(fSamplerDSHandle);
171cb93a386Sopenharmony_ci    if (!descriptorSet) {
172cb93a386Sopenharmony_ci        return false;
173cb93a386Sopenharmony_ci    }
174cb93a386Sopenharmony_ci
175cb93a386Sopenharmony_ci    for (int i = 0; i < fNumSamplers; ++i) {
176cb93a386Sopenharmony_ci        GrSamplerState state = samplerBindings[i].fState;
177cb93a386Sopenharmony_ci        GrVkTexture* texture = samplerBindings[i].fTexture;
178cb93a386Sopenharmony_ci        auto texAttachment = texture->textureImage();
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_ci        const GrVkImageView* textureView = texAttachment->textureView();
181cb93a386Sopenharmony_ci        const GrVkSampler* sampler = nullptr;
182cb93a386Sopenharmony_ci        if (fImmutableSamplers[i]) {
183cb93a386Sopenharmony_ci            sampler = fImmutableSamplers[i];
184cb93a386Sopenharmony_ci        } else {
185cb93a386Sopenharmony_ci            sampler = gpu->resourceProvider().findOrCreateCompatibleSampler(
186cb93a386Sopenharmony_ci                    state, texAttachment->ycbcrConversionInfo());
187cb93a386Sopenharmony_ci            if (!sampler) {
188cb93a386Sopenharmony_ci                descriptorSet->recycle();
189cb93a386Sopenharmony_ci                return false;
190cb93a386Sopenharmony_ci            }
191cb93a386Sopenharmony_ci        }
192cb93a386Sopenharmony_ci        SkASSERT(sampler);
193cb93a386Sopenharmony_ci
194cb93a386Sopenharmony_ci        VkDescriptorImageInfo imageInfo;
195cb93a386Sopenharmony_ci        memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo));
196cb93a386Sopenharmony_ci        imageInfo.sampler = fImmutableSamplers[i] ? VK_NULL_HANDLE : sampler->sampler();
197cb93a386Sopenharmony_ci        imageInfo.imageView = textureView->imageView();
198cb93a386Sopenharmony_ci        imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
199cb93a386Sopenharmony_ci
200cb93a386Sopenharmony_ci        VkWriteDescriptorSet writeInfo;
201cb93a386Sopenharmony_ci        memset(&writeInfo, 0, sizeof(VkWriteDescriptorSet));
202cb93a386Sopenharmony_ci        writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
203cb93a386Sopenharmony_ci        writeInfo.pNext = nullptr;
204cb93a386Sopenharmony_ci        writeInfo.dstSet = *descriptorSet->descriptorSet();
205cb93a386Sopenharmony_ci        writeInfo.dstBinding = i;
206cb93a386Sopenharmony_ci        writeInfo.dstArrayElement = 0;
207cb93a386Sopenharmony_ci        writeInfo.descriptorCount = 1;
208cb93a386Sopenharmony_ci        writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
209cb93a386Sopenharmony_ci        writeInfo.pImageInfo = &imageInfo;
210cb93a386Sopenharmony_ci        writeInfo.pBufferInfo = nullptr;
211cb93a386Sopenharmony_ci        writeInfo.pTexelBufferView = nullptr;
212cb93a386Sopenharmony_ci
213cb93a386Sopenharmony_ci        GR_VK_CALL(gpu->vkInterface(),
214cb93a386Sopenharmony_ci                   UpdateDescriptorSets(gpu->device(), 1, &writeInfo, 0, nullptr));
215cb93a386Sopenharmony_ci        commandBuffer->addResource(sampler);
216cb93a386Sopenharmony_ci        if (!fImmutableSamplers[i]) {
217cb93a386Sopenharmony_ci            sampler->unref();
218cb93a386Sopenharmony_ci        }
219cb93a386Sopenharmony_ci        commandBuffer->addResource(textureView);
220cb93a386Sopenharmony_ci        commandBuffer->addResource(texAttachment->resource());
221cb93a386Sopenharmony_ci    }
222cb93a386Sopenharmony_ci    if (fNumSamplers == 1) {
223cb93a386Sopenharmony_ci        GrSamplerState state = samplerBindings[0].fState;
224cb93a386Sopenharmony_ci        GrVkTexture* texture = samplerBindings[0].fTexture;
225cb93a386Sopenharmony_ci        texture->addDescriptorSetToCache(descriptorSet, state);
226cb93a386Sopenharmony_ci    }
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_ci    commandBuffer->bindDescriptorSets(gpu, fPipeline->layout(), kSamplerDSIdx, /*setCount=*/1,
229cb93a386Sopenharmony_ci                                      descriptorSet->descriptorSet(),
230cb93a386Sopenharmony_ci                                      /*dynamicOffsetCount=*/0, /*dynamicOffsets=*/nullptr);
231cb93a386Sopenharmony_ci    commandBuffer->addRecycledResource(descriptorSet);
232cb93a386Sopenharmony_ci    descriptorSet->recycle();
233cb93a386Sopenharmony_ci    return true;
234cb93a386Sopenharmony_ci}
235cb93a386Sopenharmony_ci
236cb93a386Sopenharmony_cibool GrVkPipelineState::setAndBindInputAttachment(GrVkGpu* gpu,
237cb93a386Sopenharmony_ci                                                  gr_rp<const GrVkDescriptorSet> inputDescSet,
238cb93a386Sopenharmony_ci                                                  GrVkCommandBuffer* commandBuffer) {
239cb93a386Sopenharmony_ci    SkASSERT(inputDescSet);
240cb93a386Sopenharmony_ci    commandBuffer->bindDescriptorSets(gpu, fPipeline->layout(), GrVkUniformHandler::kInputDescSet,
241cb93a386Sopenharmony_ci                                      /*setCount=*/1, inputDescSet->descriptorSet(),
242cb93a386Sopenharmony_ci                                      /*dynamicOffsetCount=*/0, /*dynamicOffsets=*/nullptr);
243cb93a386Sopenharmony_ci    // We don't add the input resource to the command buffer to track since the input will be
244cb93a386Sopenharmony_ci    // the same as the color attachment which is already tracked on the command buffer.
245cb93a386Sopenharmony_ci    commandBuffer->addRecycledResource(std::move(inputDescSet));
246cb93a386Sopenharmony_ci    return true;
247cb93a386Sopenharmony_ci}
248cb93a386Sopenharmony_ci
249cb93a386Sopenharmony_civoid GrVkPipelineState::setRenderTargetState(SkISize colorAttachmentDimensions,
250cb93a386Sopenharmony_ci                                             GrSurfaceOrigin origin) {
251cb93a386Sopenharmony_ci    // Set RT adjustment and RT flip
252cb93a386Sopenharmony_ci    SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid());
253cb93a386Sopenharmony_ci    if (fRenderTargetState.fRenderTargetOrigin != origin ||
254cb93a386Sopenharmony_ci        fRenderTargetState.fRenderTargetSize != colorAttachmentDimensions) {
255cb93a386Sopenharmony_ci        fRenderTargetState.fRenderTargetSize = colorAttachmentDimensions;
256cb93a386Sopenharmony_ci        fRenderTargetState.fRenderTargetOrigin = origin;
257cb93a386Sopenharmony_ci
258cb93a386Sopenharmony_ci        // The client will mark a swap buffer as kTopLeft when making a SkSurface because
259cb93a386Sopenharmony_ci        // Vulkan's framebuffer space has (0, 0) at the top left. This agrees with Skia's device
260cb93a386Sopenharmony_ci        // coords and with Vulkan's NDC that has (-1, -1) in the top left. So a flip is needed when
261cb93a386Sopenharmony_ci        // surface origin is kBottomLeft rather than kTopLeft.
262cb93a386Sopenharmony_ci        bool flip = (origin == kBottomLeft_GrSurfaceOrigin);
263cb93a386Sopenharmony_ci        std::array<float, 4> v = SkSL::Compiler::GetRTAdjustVector(colorAttachmentDimensions, flip);
264cb93a386Sopenharmony_ci        fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, v.data());
265cb93a386Sopenharmony_ci        if (fBuiltinUniformHandles.fRTFlipUni.isValid()) {
266cb93a386Sopenharmony_ci            std::array<float, 2> d =
267cb93a386Sopenharmony_ci                    SkSL::Compiler::GetRTFlipVector(colorAttachmentDimensions.height(), flip);
268cb93a386Sopenharmony_ci            fDataManager.set2fv(fBuiltinUniformHandles.fRTFlipUni, 1, d.data());
269cb93a386Sopenharmony_ci        }
270cb93a386Sopenharmony_ci    }
271cb93a386Sopenharmony_ci}
272cb93a386Sopenharmony_ci
273cb93a386Sopenharmony_civoid GrVkPipelineState::bindPipeline(const GrVkGpu* gpu, GrVkCommandBuffer* commandBuffer) {
274cb93a386Sopenharmony_ci    commandBuffer->bindPipeline(gpu, fPipeline);
275cb93a386Sopenharmony_ci}
276