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