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